lucadeal 0.2.7 → 0.2.16

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: c9b1e922691e9d8fbc64c992e50e39068bd2652590b601ec70a13a3a49ede551
4
- data.tar.gz: cbecc49c20bbe61e7d1920f61ee3357d53ff4f44b7fc3582ee92e716a0cc670a
3
+ metadata.gz: 5f17d75af6f101c60eced0ecfb770e39ac66b0f35725a6976f135216a0c75099
4
+ data.tar.gz: d3e60d51908e78ab72e177f29affc26864744afb584d1c5dadd507b18ff888f6
5
5
  SHA512:
6
- metadata.gz: f8e181b5272c1ced02af7b0fa5523004b352301ee9310d5aebbe8918ab7899d13a75c337c8627765f8be3fdfe9b9415598e372d8bc98b45b3b4f53615a8731d2
7
- data.tar.gz: e491c40bff3806dc911df1aae738d858c8e6537a992aa9b996ffeff0fa7ab83010d7f486a840556d6d08330097fa890ffb02a4ad0881064fd9a98a2df8d7cbcb
6
+ metadata.gz: bd534c31a33405478cdeba88777481f5c17af6337cf743e2d16a8e5027209a65d1efb8329cf7f6e72318dfea8c3daa1965d9cf1e833ce93b85d24925c17638f6
7
+ data.tar.gz: f1d809de08ce94cf7da913c5bc733515f95bba596dc155596880cb4776837113c36f93ee4247c35fe34990f2a45fd758df1bddec3d2e587d182062cdb5893c60
@@ -0,0 +1,11 @@
1
+ ## LucaDeal 0.2.14
2
+
3
+ * Introduce Product for selling items template.
4
+
5
+ ## LucaDeal 0.2.12
6
+
7
+ * Introduce Sales fee calculation.
8
+
9
+ ## LucaDeal 0.2.10
10
+
11
+ * items can have one time cost at initial month of contract.
data/README.md CHANGED
@@ -1,15 +1,15 @@
1
- # Luca::Deal
1
+ # LucaDeal
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/luca/deal`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ [![Gem Version](https://badge.fury.io/rb/lucadeal.svg)](https://badge.fury.io/rb/lucadeal)
4
4
 
5
- TODO: Delete this and the text above, and describe your gem
5
+ LucaDeal is Sales contract management application.
6
6
 
7
7
  ## Installation
8
8
 
9
9
  Add this line to your application's Gemfile:
10
10
 
11
11
  ```ruby
12
- gem 'luca-deal'
12
+ gem 'lucadeal'
13
13
  ```
14
14
 
15
15
  And then execute:
@@ -18,12 +18,141 @@ And then execute:
18
18
 
19
19
  Or install it yourself as:
20
20
 
21
- $ gem install luca-deal
21
+ $ gem install lucadeal
22
22
 
23
23
  ## Usage
24
24
 
25
25
  TODO: Write usage instructions here
26
26
 
27
+
28
+ ## Data Structure
29
+
30
+ Records are stored in YAML format. On historical records, see [LucaRecord](../lucarecord/README.md#historical-field).
31
+
32
+ ### Customer
33
+
34
+ Customer consists of label information.
35
+
36
+ | Top level | Second level | | historical | Description |
37
+ |-----------|--------------|------|------------|--------------------------------|
38
+ | id | | auto | | uuid |
39
+ | name | | must | x | customer's name |
40
+ | address | | | x | |
41
+ | address2 | | | x | |
42
+ | contacts | | | | Array of contact information |
43
+ | | mail | | | mail address receiving invoice |
44
+
45
+
46
+ ### Product
47
+
48
+ Product is items template referred by Contract.
49
+
50
+ | Top level | Second level | | historical | Description |
51
+ |-----------|--------------|----------|------------|------------------------------------------------------------------------------------------------------|
52
+ | id | | auto | | uuid |
53
+ | name | | | x | Product name. |
54
+ | items | | | | Array of items. |
55
+ | | name | | x | Item name. |
56
+ | | price | | x | Item price. |
57
+ | | qty | optional | x | quantity. Default: 1. |
58
+ | | type | optional | | If 'initial', this item is treated as initial cost, applied only on the first month of the contract. |
59
+
60
+
61
+ ### Contract
62
+
63
+ Contract is core object for calculation. Common fields are as follows:
64
+
65
+ | Top level | Second level | | historical | Description |
66
+ |-------------|---------------|----------|------------|------------------------------------------------------------------------------------------------------|
67
+ | id | | auto | | uuid |
68
+ | customer_id | | must | x | customer's uuid |
69
+ | terms | | | | |
70
+ | | effective | must | | Start date of the contract. |
71
+ | | defunct | | | End date of the contract. |
72
+
73
+ Fields for subscription customers are as bellows:
74
+
75
+ | Top level | Second level | | historical | Description |
76
+ |-----------|---------------|----------|------------|------------------------------------------------------------------------------------------------------|
77
+ | terms | | | | |
78
+ | | billing_cycle | optional | | If 'monthly', invoices are generated on each month. |
79
+ | | category | optional | | Default: 'subscription' |
80
+ | products | | | | Array of products. |
81
+ | | id | | | reference for Product |
82
+ | items | | | | Array of items. |
83
+ | | name | | x | Item name. |
84
+ | | price | | x | Item price. |
85
+ | | qty | optional | x | quantity. Default: 1. |
86
+ | | type | optional | | If 'initial', this item is treated as initial cost, applied only on the first month of the contract. |
87
+ | sales_fee | | optional | | |
88
+ | | id | | | contract id of fee with sales partner. |
89
+
90
+
91
+ Fields for sales fee are as bellows:
92
+
93
+ | Top level | Second level | | historical | Description |
94
+ |-----------|--------------|----------|------------|-------------------------------------------------------------------------------------|
95
+ | terms | | | | |
96
+ | | category | | | If 'sales_fee', contract is treated as selling commission. |
97
+ | rate | | optional | | |
98
+ | | default | | | sales fee rate. |
99
+ | | initial | | | sales fee rate for items of type=initial. |
100
+
101
+
102
+ ### Invoice
103
+
104
+ Invoice is basically auto generated from Customer and Contract objects.
105
+
106
+ | Top level | Second level | Description |
107
+ |------------|--------------|------------------------------------------|
108
+ | id | | uuid |
109
+ | issue_date | | |
110
+ | due_date | | |
111
+ | customer | | |
112
+ | | id | customer's uuid |
113
+ | | name | customer name |
114
+ | | address | |
115
+ | | address2 | |
116
+ | | to | Array of mail addresses |
117
+ | items | | Array of items. |
118
+ | | name | Item name. |
119
+ | | price | Item price. |
120
+ | | qty | quantity. Default: 1. |
121
+ | | type | |
122
+ | | product_id | refrence for Product |
123
+ | subtotal | | Array of subtotal by tax category. |
124
+ | | items | amount of items |
125
+ | | tax | amount of tax |
126
+ | | rate | applied tax category. Default: 'default' |
127
+ | sales_fee | | |
128
+ | | id | contract id of fee with sales partner. |
129
+ | status | | Array of status with timestamp. |
130
+
131
+
132
+ ### Fee
133
+
134
+ Fee is basically auto generated from Contract and Invoice objects.
135
+
136
+ | Top level | Second level | Description |
137
+ |-----------|--------------|----------------------------------------------|
138
+ | id | | uuid |
139
+ | sales_fee | | |
140
+ | | id | contract id with sales partner. |
141
+ | | default.fee | Amount of fee on dafault rate. |
142
+ | | default.tax | Amount of tax for default.fee. |
143
+ | | initial.fee | Amount of fee on initial cost. |
144
+ | | initial.tax | Amount of tax for initial.fee. |
145
+ | invoice | | Carbon copy of Invoice attributes. |
146
+ | | id | |
147
+ | | contract_id | |
148
+ | | issue_date | |
149
+ | | due_date | |
150
+ | customer | | Carbon copy of Invoice customer except 'to'. |
151
+ | items | | Carbon copy of Invoice items. |
152
+ | subtotal | | Carbon copy of Invoice subtotal. |
153
+ | status | | Array of status with timestamp. |
154
+
155
+
27
156
  ## Development
28
157
 
29
158
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -32,4 +161,4 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
32
161
 
33
162
  ## Contributing
34
163
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/luca-deal.
164
+ Bug reports and pull requests are welcome on GitHub at https://github.com/chumaltd/luca .
@@ -11,7 +11,7 @@ def customer(args = nil, params = {})
11
11
  LucaDeal::Customer.new.list_name
12
12
  when 'create'
13
13
  if params['name']
14
- id = LucaDeal::Customer.new.generate!(params['name'])
14
+ id = LucaDeal::Customer.create(name: params['name'])
15
15
  puts "Successfully generated Customer #{id}" if id
16
16
  puts 'Edit customer detail.' if id
17
17
  else
@@ -28,7 +28,7 @@ def contract(args = nil, params = {})
28
28
  case params['mode']
29
29
  when 'create'
30
30
  if params['customer_id']
31
- id = LucaDeal::Contract.new.generate!(params['customer_id'])
31
+ id = LucaDeal::Contract.new.generate!(params['customer_id'], params['category'])
32
32
  puts "Successfully generated Contract #{id}" if id
33
33
  puts 'Conditions are tentative. Edit contract detail.' if id
34
34
  else
@@ -87,6 +87,9 @@ when 'contract'
87
87
  params['mode'] = 'create'
88
88
  params['customer_id'] = v
89
89
  end
90
+ opt.on('--salesfee', 'create contract as sales fee definition') do |_v|
91
+ params['category'] = 'sales_fee'
92
+ end
90
93
  args = opt.parse(ARGV)
91
94
  contract(args, params)
92
95
  end
@@ -6,6 +6,8 @@ require 'luca_deal/version'
6
6
  module LucaDeal
7
7
  autoload :Customer, 'luca_deal/customer'
8
8
  autoload :Contract, 'luca_deal/contract'
9
+ autoload :Fee, 'luca_deal/fee'
9
10
  autoload :Invoice, 'luca_deal/invoice'
11
+ autoload :Product, 'luca_deal/product'
10
12
  autoload :Setup, 'luca_deal/setup'
11
13
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'luca_deal/version'
2
4
 
3
5
  require 'yaml'
@@ -7,40 +9,85 @@ require 'luca_record'
7
9
  module LucaDeal
8
10
  class Contract < LucaRecord::Base
9
11
  @dirname = 'contracts'
12
+ @required = ['customer_id', 'terms']
10
13
 
11
14
  def initialize(date = nil)
12
15
  @date = date ? Date.parse(date) : Date.today
13
16
  @pjdir = Pathname(Dir.pwd)
14
17
  end
15
18
 
19
+ # returns active contracts on specified date.
20
+ #
21
+ def self.asof(year, month, day)
22
+ return enum_for(:asof, year, month, day) unless block_given?
23
+
24
+ new("#{year}-#{month}-#{day}").active do |contract|
25
+ yield contract
26
+ end
27
+ end
28
+
16
29
  #
17
30
  # collect active contracts
18
31
  #
19
32
  def active
33
+ return enum_for(:active) unless block_given?
34
+
20
35
  self.class.all do |data|
21
- contract = parse_current(data)
22
- next if !self.class.active_period?(contract)
36
+ next if !active_period?(data.dig('terms'))
23
37
 
24
- yield contract
38
+ contract = parse_current(data)
39
+ contract['items'] = contract['items']&.map { |item| parse_current(item) }
40
+ # TODO: handle sales_fee rate change
41
+ contract['rate'] = contract['rate']
42
+ yield contract.compact
25
43
  end
26
44
  end
27
45
 
28
- def generate!(customer_id)
46
+ def generate!(customer_id, mode = 'subscription')
29
47
  LucaDeal::Customer.find(customer_id) do |customer|
30
48
  current_customer = parse_current(customer)
31
- obj = { 'customer_id' => current_customer['id'], 'customer_name' => current_customer['name'] }
49
+ if mode == 'sales_fee'
50
+ obj = salesfee_template
51
+ else
52
+ obj = monthly_template
53
+ end
54
+ obj.merge!({ 'customer_id' => current_customer['id'], 'customer_name' => current_customer['name'] })
55
+ obj['terms'] ||= {}
56
+ obj['terms']['effective'] = @date
57
+ self.class.create(obj)
58
+ end
59
+ end
60
+
61
+ def active_period?(dat)
62
+ unless dat.dig('defunct').nil?
63
+ defunct = dat.dig('defunct').respond_to?(:year) ? dat.dig('defunct') : Date.parse(dat.dig('defunct'))
64
+ return false if @date > defunct
65
+ end
66
+ effective = dat.dig('effective').respond_to?(:year) ? dat.dig('effective') : Date.parse(dat.dig('effective'))
67
+ @date >= effective
68
+ end
69
+
70
+ private
71
+
72
+ def monthly_template
73
+ {}.tap do |obj|
32
74
  obj['items'] = [{
33
75
  'name' => '_ITEM_NAME_FOR_INVOICE_',
34
76
  'qty' => 1,
35
77
  'price' => 0
36
78
  }]
37
- obj['terms'] = { 'billing_cycle' => 'monthly', 'effective' => @date }
38
- self.class.create(obj)
79
+ obj['terms'] = { 'billing_cycle' => 'monthly' }
39
80
  end
40
81
  end
41
82
 
42
- def self.active_period?(dat)
43
- !dat.dig('terms').nil?
83
+ def salesfee_template
84
+ {}.tap do |obj|
85
+ obj['rate'] = {
86
+ 'default' => '0.2',
87
+ 'initial' => '0.2'
88
+ }
89
+ obj['terms'] = { 'category' => 'sales_fee' }
90
+ end
44
91
  end
45
92
  end
46
93
  end
@@ -10,6 +10,7 @@ require 'luca_record'
10
10
  module LucaDeal
11
11
  class Customer < LucaRecord::Base
12
12
  @dirname = 'customers'
13
+ @required = ['name']
13
14
 
14
15
  def initialize(pjdir = nil)
15
16
  @date = Date.today
@@ -21,17 +22,20 @@ module LucaDeal
21
22
  YAML.dump(list).tap { |l| puts l }
22
23
  end
23
24
 
24
- def generate!(name)
25
- contact = {
25
+ def self.create(obj)
26
+ raise ':name is required' if obj[:name].nil?
27
+
28
+ contacts = obj[:contact]&.map { |c| { 'mail' => c[:mail] } }&.compact
29
+ contacts ||= [{
26
30
  'mail' => '_MAIL_ADDRESS_FOR_CONTACT_'
31
+ }]
32
+ h = {
33
+ 'name' => obj[:name],
34
+ 'address' => obj[:address] || '_CUSTOMER_ADDRESS_FOR_INVOICE_',
35
+ 'address2' => obj[:address2] || '_CUSTOMER_ADDRESS_FOR_INVOICE_',
36
+ 'contacts' => contacts
27
37
  }
28
- obj = {
29
- 'name' => name,
30
- 'address' => '_CUSTOMER_ADDRESS_FOR_INVOICE_',
31
- 'address2' => '_CUSTOMER_ADDRESS_FOR_INVOICE_',
32
- 'contacts' => [contact]
33
- }
34
- self.class.create(obj)
38
+ super(h)
35
39
  end
36
40
  end
37
41
  end
@@ -0,0 +1,118 @@
1
+ require 'luca_deal/version'
2
+
3
+ require 'mail'
4
+ require 'yaml'
5
+ require 'pathname'
6
+ require 'bigdecimal'
7
+ require 'luca_support/config'
8
+ require 'luca_support/mail'
9
+ require 'luca_deal'
10
+
11
+ module LucaDeal
12
+ class Fee < LucaRecord::Base
13
+ @dirname = 'fees'
14
+
15
+ def initialize(date = nil)
16
+ @date = issue_date(date)
17
+ @config = load_config('config.yml')
18
+ end
19
+
20
+ # calculate fee, based on invoices
21
+ #
22
+ def monthly_fee
23
+ LucaDeal::Contract.asof(@date.year, @date.month, @date.day) do |contract|
24
+ next if contract.dig('terms', 'category') != 'sales_fee'
25
+
26
+ @rate = { 'default' => BigDecimal(contract.dig('rate', 'default')) }
27
+ @rate['initial'] = contract.dig('rate', 'initial') ? BigDecimal(contract.dig('rate', 'initial')) : @rate['default']
28
+
29
+ LucaDeal::Invoice.asof(@date.year, @date.month) do |invoice|
30
+ next if invoice.dig('sales_fee', 'id') != contract['id']
31
+ next if duplicated_contract? invoice['contract_id']
32
+
33
+ fee = invoice.dup
34
+ fee['invoice'] = {}.tap do |f_invoice|
35
+ %w[id contract_id issue_date due_date].each do |i|
36
+ f_invoice[i] = invoice[i]
37
+ fee.delete i
38
+ end
39
+ end
40
+ fee['id'] = issue_random_id
41
+ fee['customer'].delete('to')
42
+ fee['sales_fee'].merge! subtotal(fee['items'])
43
+ gen_fee!(fee)
44
+ end
45
+ end
46
+ end
47
+
48
+ def get_customer(id)
49
+ {}.tap do |res|
50
+ LucaDeal::Customer.find(id) do |dat|
51
+ customer = parse_current(dat)
52
+ res['id'] = customer['id']
53
+ res['name'] = customer.dig('name')
54
+ res['address'] = customer.dig('address')
55
+ res['address2'] = customer.dig('address2')
56
+ res['to'] = customer.dig('contacts').map { |h| take_current(h, 'mail') }.compact
57
+ end
58
+ end
59
+ end
60
+
61
+ def gen_fee!(fee)
62
+ id = fee.dig('invoice', 'contract_id')
63
+ self.class.create(fee, date: @date, codes: Array(id))
64
+ end
65
+
66
+ private
67
+
68
+ def lib_path
69
+ __dir__
70
+ end
71
+
72
+ # load user company profile from config.
73
+ #
74
+ def set_company
75
+ {}.tap do |h|
76
+ h['name'] = @config.dig('company', 'name')
77
+ h['address'] = @config.dig('company', 'address')
78
+ h['address2'] = @config.dig('company', 'address2')
79
+ end
80
+ end
81
+
82
+ # calc fee & tax amount by tax category
83
+ #
84
+ def subtotal(items)
85
+ {}.tap do |subtotal|
86
+ items.each do |i|
87
+ rate = i.dig('type') || 'default'
88
+ subtotal[rate] = { 'fee' => 0, 'tax' => 0 } if subtotal.dig(rate).nil?
89
+ subtotal[rate]['fee'] += i['qty'] * i['price'] * @rate[rate]
90
+ end
91
+ subtotal.each do |rate, amount|
92
+ amount['tax'] = (amount['fee'] * load_tax_rate(rate)).to_i
93
+ amount['fee'] = amount['fee'].to_i
94
+ end
95
+ end
96
+ end
97
+
98
+ def issue_date(date)
99
+ base = date.nil? ? Date.today : Date.parse(date)
100
+ Date.new(base.year, base.month, -1)
101
+ end
102
+
103
+ # load Tax Rate from config.
104
+ #
105
+ def load_tax_rate(name)
106
+ return 0 if @config.dig('tax_rate', name).nil?
107
+
108
+ BigDecimal(take_current(@config['tax_rate'], name).to_s)
109
+ end
110
+
111
+ def duplicated_contract?(id)
112
+ self.class.asof(@date.year, @date.month, @date.day) do |_f, path|
113
+ return true if path.include?(id)
114
+ end
115
+ false
116
+ end
117
+ end
118
+ end
@@ -12,6 +12,7 @@ require 'luca_record'
12
12
  module LucaDeal
13
13
  class Invoice < LucaRecord::Base
14
14
  @dirname = 'invoices'
15
+ @required = ['issue_date', 'customer', 'items', 'subtotal']
15
16
 
16
17
  def initialize(date = nil)
17
18
  @date = issue_date(date)
@@ -58,7 +59,6 @@ module LucaDeal
58
59
  mail
59
60
  end
60
61
 
61
- #
62
62
  # Output seriarized invoice data to stdout.
63
63
  # Returns previous N months on multiple count
64
64
  #
@@ -97,7 +97,7 @@ module LucaDeal
97
97
  collection << stat
98
98
  end
99
99
  end
100
- puts YAML.dump(collection)
100
+ puts YAML.dump(LucaSupport::Code.readable(collection))
101
101
  end
102
102
  end
103
103
 
@@ -113,12 +113,12 @@ module LucaDeal
113
113
  invoice['customer'] = get_customer(contract.dig('customer_id'))
114
114
  invoice['due_date'] = due_date(@date)
115
115
  invoice['issue_date'] = @date
116
- invoice['items'] = contract.dig('items').map do |item|
117
- {}.tap do |h|
118
- h['name'] = item.dig('name')
119
- h['price'] = item.dig('price')
120
- h['qty'] = item.dig('qty')
121
- end
116
+ invoice['sales_fee'] = contract['sales_fee'] if contract.dig('sales_fee')
117
+ invoice['items'] = get_products(contract['products'])
118
+ .concat(contract['items']&.map { |i| i['qty'] ||= 1; i } || [])
119
+ .compact
120
+ invoice['items'].reject! do |item|
121
+ item.dig('type') == 'initial' && subsequent_month?(contract.dig('terms', 'effective'))
122
122
  end
123
123
  invoice['subtotal'] = subtotal(invoice['items'])
124
124
  .map { |k, v| v.tap { |dat| dat['rate'] = k } }
@@ -126,7 +126,6 @@ module LucaDeal
126
126
  end
127
127
  end
128
128
 
129
- #
130
129
  # set variables for ERB template
131
130
  #
132
131
  def invoice_vars(invoice_dat)
@@ -151,9 +150,23 @@ module LucaDeal
151
150
  end
152
151
  end
153
152
 
153
+ def get_products(products)
154
+ return [] if products.nil?
155
+
156
+ [].tap do |res|
157
+ products.each do |product|
158
+ LucaDeal::Product.find(product['id'])['items'].each do |item|
159
+ item['product_id'] = product['id']
160
+ item['qty'] ||= 1
161
+ res << item
162
+ end
163
+ end
164
+ end
165
+ end
166
+
154
167
  def gen_invoice!(invoice)
155
168
  id = invoice.dig('contract_id')
156
- self.class.create_record!(invoice, @date, Array(id))
169
+ self.class.create(invoice, date: @date, codes: Array(id))
157
170
  end
158
171
 
159
172
  def issue_date(date)
@@ -172,7 +185,6 @@ module LucaDeal
172
185
  __dir__
173
186
  end
174
187
 
175
- #
176
188
  # load user company profile from config.
177
189
  #
178
190
  def set_company
@@ -183,23 +195,22 @@ module LucaDeal
183
195
  end
184
196
  end
185
197
 
186
- #
187
198
  # calc items & tax amount by tax category
188
199
  #
189
200
  def subtotal(items)
190
201
  {}.tap do |subtotal|
191
202
  items.each do |i|
192
203
  rate = i.dig('tax') || 'default'
204
+ qty = i['qty'] || BigDecimal('1')
193
205
  subtotal[rate] = { 'items' => 0, 'tax' => 0 } if subtotal.dig(rate).nil?
194
- subtotal[rate]['items'] += i['qty'] * i['price']
206
+ subtotal[rate]['items'] += i['price'] * qty
195
207
  end
196
208
  subtotal.each do |rate, amount|
197
- amount['tax'] = (amount['items'] * load_tax_rate(rate)).to_i
209
+ amount['tax'] = (amount['items'] * load_tax_rate(rate))
198
210
  end
199
211
  end
200
212
  end
201
213
 
202
- #
203
214
  # load Tax Rate from config.
204
215
  #
205
216
  def load_tax_rate(name)
@@ -218,5 +229,10 @@ module LucaDeal
218
229
  end
219
230
  false
220
231
  end
232
+
233
+ def subsequent_month?(effective_date)
234
+ effective_date = Date.parse(effective_date) unless effective_date.respond_to? :year
235
+ effective_date.year != @date.year || effective_date.month != @date.month
236
+ end
221
237
  end
222
238
  end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'luca_deal/version'
4
+
5
+ require 'date'
6
+ require 'yaml'
7
+ require 'pathname'
8
+ require 'luca_record'
9
+
10
+ module LucaDeal
11
+ class Product < LucaRecord::Base
12
+ @dirname = 'products'
13
+ @required = ['items']
14
+
15
+ def list_name
16
+ list = self.class.all.map { |dat| parse_current(dat) }
17
+ YAML.dump(list).tap { |l| puts l }
18
+ end
19
+
20
+ # Save data with hash in Product format. Simple format is also available as bellows:
21
+ # {
22
+ # name: 'item_name(required)', price: 'item_price', qty: 'item_qty',
23
+ # initial: { name: 'item_name', price: 'item_price', qty: 'item_qty' }
24
+ # }
25
+ def self.create(obj)
26
+ if obj[:name].nil?
27
+ h = obj
28
+ else
29
+ items = [{
30
+ 'name' => obj[:name],
31
+ 'price' => obj[:price] || 0,
32
+ 'qty' => obj[:qty] || 1
33
+ }]
34
+ if obj[:initial]
35
+ items << {
36
+ 'name' => obj.dig(:initial, :name),
37
+ 'price' => obj.dig(:initial, :price) || 0,
38
+ 'qty' => obj.dig(:initial, :qty) || 1,
39
+ 'type' => 'initial'
40
+ }
41
+ end
42
+ h = {
43
+ 'name' => obj[:name],
44
+ 'items' => items
45
+ }
46
+ end
47
+ super(h)
48
+ end
49
+ end
50
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "luca_deal/version"
3
+ require 'luca_deal/version'
4
4
  require 'fileutils'
5
5
 
6
6
  module LucaDeal
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LucaDeal
4
- VERSION = "0.2.7"
4
+ VERSION = '0.2.16'
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.2.7
4
+ version: 0.2.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chuma Takahiro
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-10-07 00:00:00.000000000 Z
11
+ date: 2020-11-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: lucarecord
@@ -28,14 +28,14 @@ dependencies:
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '1.17'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1.17'
41
41
  - !ruby/object:Gem::Dependency
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '5.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: 12.3.3
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: 12.3.3
55
69
  description: 'Deal with contracts
56
70
 
57
71
  '
@@ -69,7 +83,9 @@ files:
69
83
  - lib/luca_deal.rb
70
84
  - lib/luca_deal/contract.rb
71
85
  - lib/luca_deal/customer.rb
86
+ - lib/luca_deal/fee.rb
72
87
  - lib/luca_deal/invoice.rb
88
+ - lib/luca_deal/product.rb
73
89
  - lib/luca_deal/setup.rb
74
90
  - lib/luca_deal/templates/.keep
75
91
  - lib/luca_deal/templates/config.yml