lucadeal 0.2.9 → 0.2.13
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +131 -7
- data/exe/luca-deal +1 -1
- data/lib/luca_deal.rb +2 -0
- data/lib/luca_deal/contract.rb +33 -11
- data/lib/luca_deal/customer.rb +12 -9
- data/lib/luca_deal/fee.rb +118 -0
- data/lib/luca_deal/invoice.rb +11 -7
- data/lib/luca_deal/product.rb +42 -0
- data/lib/luca_deal/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9a2f79f88f7a7047f07f4c2137888f43e29cec70129e0b8d79544d4c8137e2f4
|
4
|
+
data.tar.gz: 8d3d2dbf4908f7e5851f64003eaf39fd455f34c1e8f51c07dff7685fa913e036
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: feb4db73cf4f5d59a1caafb5e18c7e00460e9903244ba9a43ac1781b8a2ffd7b6465d95a309211e98e487b5b77daa5e1463c4647313f001b80f779c2e23354ad
|
7
|
+
data.tar.gz: 6204831c6bb54534a3527c7280a5c761bfb422a52831d1dd4d26b484fc221ddc78a979d5b66e42263c1a6d76ebeb140fefcb54c63a203d8b292e6ce40e5e2e05
|
data/README.md
CHANGED
@@ -1,15 +1,13 @@
|
|
1
|
-
#
|
1
|
+
# LucaDeal
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
TODO: Delete this and the text above, and describe your gem
|
3
|
+
LucaDeal is Sales contract management application.
|
6
4
|
|
7
5
|
## Installation
|
8
6
|
|
9
7
|
Add this line to your application's Gemfile:
|
10
8
|
|
11
9
|
```ruby
|
12
|
-
gem '
|
10
|
+
gem 'lucadeal'
|
13
11
|
```
|
14
12
|
|
15
13
|
And then execute:
|
@@ -18,12 +16,138 @@ And then execute:
|
|
18
16
|
|
19
17
|
Or install it yourself as:
|
20
18
|
|
21
|
-
$ gem install
|
19
|
+
$ gem install lucadeal
|
22
20
|
|
23
21
|
## Usage
|
24
22
|
|
25
23
|
TODO: Write usage instructions here
|
26
24
|
|
25
|
+
|
26
|
+
## Data Structure
|
27
|
+
|
28
|
+
Records are stored in YAML format. On historical records, see [LucaRecord](../lucarecord/README.md#historical-field).
|
29
|
+
|
30
|
+
### Customer
|
31
|
+
|
32
|
+
Customer consists of label information.
|
33
|
+
|
34
|
+
| Top level | Second level | | historical | Description |
|
35
|
+
|-----------|--------------|------|------------|--------------------------------|
|
36
|
+
| id | | auto | | uuid |
|
37
|
+
| name | | must | x | customer's name |
|
38
|
+
| address | | | x | |
|
39
|
+
| address2 | | | x | |
|
40
|
+
| contacts | | | | Array of contact information |
|
41
|
+
| | mail | | | mail address receiving invoice |
|
42
|
+
|
43
|
+
|
44
|
+
### Product
|
45
|
+
|
46
|
+
Product is items template referred by Contract.
|
47
|
+
|
48
|
+
| Top level | Second level | | historical | Description |
|
49
|
+
|-----------|--------------|----------|------------|------------------------------------------------------------------------------------------------------|
|
50
|
+
| id | | auto | | uuid |
|
51
|
+
| name | | | x | Product name. |
|
52
|
+
| items | | | | Array of items. |
|
53
|
+
| | name | | x | Item name. |
|
54
|
+
| | price | | x | Item price. |
|
55
|
+
| | qty | optional | x | quantity. Default: 1. |
|
56
|
+
| | type | optional | | If 'initial', this item is treated as initial cost, applied only on the first month of the contract. |
|
57
|
+
|
58
|
+
|
59
|
+
### Contract
|
60
|
+
|
61
|
+
Contract is core object for calculation. Common fields are as follows:
|
62
|
+
|
63
|
+
| Top level | Second level | | historical | Description |
|
64
|
+
|-------------|---------------|----------|------------|------------------------------------------------------------------------------------------------------|
|
65
|
+
| id | | auto | | uuid |
|
66
|
+
| customer_id | | must | x | customer's uuid |
|
67
|
+
| terms | | | | |
|
68
|
+
| | effective | must | | Start date of the contract. |
|
69
|
+
| | defunct | | | End date of the contract. |
|
70
|
+
|
71
|
+
Fields for subscription customers are as bellows:
|
72
|
+
|
73
|
+
| Top level | Second level | | historical | Description |
|
74
|
+
|-----------|---------------|----------|------------|------------------------------------------------------------------------------------------------------|
|
75
|
+
| terms | | | | |
|
76
|
+
| | billing_cycle | optional | | If 'monthly', invoices are generated on each month. |
|
77
|
+
| | category | optional | | Default: 'subscription' |
|
78
|
+
| items | | | | Array of items. |
|
79
|
+
| | name | | x | Item name. |
|
80
|
+
| | price | | x | Item price. |
|
81
|
+
| | qty | optional | x | quantity. Default: 1. |
|
82
|
+
| | type | optional | | If 'initial', this item is treated as initial cost, applied only on the first month of the contract. |
|
83
|
+
| sales_fee | | optional | | |
|
84
|
+
| | id | | | contract id of fee with sales partner. |
|
85
|
+
|
86
|
+
|
87
|
+
Fields for sales fee are as bellows:
|
88
|
+
|
89
|
+
| Top level | Second level | | historical | Description |
|
90
|
+
|-----------|--------------|----------|------------|-------------------------------------------------------------------------------------|
|
91
|
+
| terms | | | | |
|
92
|
+
| | category | | | If 'sales_fee', contract is treated as selling commission. |
|
93
|
+
| rate | | optional | | |
|
94
|
+
| | default | | | sales fee rate. |
|
95
|
+
| | initial | | | sales fee rate for items of type=initial. |
|
96
|
+
|
97
|
+
|
98
|
+
### Invoice
|
99
|
+
|
100
|
+
Invoice is basically auto generated from Customer and Contract objects.
|
101
|
+
|
102
|
+
| Top level | Second level | Description |
|
103
|
+
|------------|--------------|------------------------------------------|
|
104
|
+
| id | | uuid |
|
105
|
+
| issue_date | | |
|
106
|
+
| due_date | | |
|
107
|
+
| customer | | |
|
108
|
+
| | id | customer's uuid |
|
109
|
+
| | name | customer name |
|
110
|
+
| | address | |
|
111
|
+
| | address2 | |
|
112
|
+
| | to | Array of mail addresses |
|
113
|
+
| items | | Array of items. |
|
114
|
+
| | name | Item name. |
|
115
|
+
| | price | Item price. |
|
116
|
+
| | qty | quantity. Default: 1. |
|
117
|
+
| | type | |
|
118
|
+
| subtotal | | Array of subtotal by tax category. |
|
119
|
+
| | items | amount of items |
|
120
|
+
| | tax | amount of tax |
|
121
|
+
| | rate | applied tax category. Default: 'default' |
|
122
|
+
| sales_fee | | |
|
123
|
+
| | id | contract id of fee with sales partner. |
|
124
|
+
| status | | Array of status with timestamp. |
|
125
|
+
|
126
|
+
|
127
|
+
### Fee
|
128
|
+
|
129
|
+
Fee is basically auto generated from Contract and Invoice objects.
|
130
|
+
|
131
|
+
| Top level | Second level | Description |
|
132
|
+
|-----------|--------------|----------------------------------------------|
|
133
|
+
| id | | uuid |
|
134
|
+
| sales_fee | | |
|
135
|
+
| | id | contract id with sales partner. |
|
136
|
+
| | default.fee | Amount of fee on dafault rate. |
|
137
|
+
| | default.tax | Amount of tax for default.fee. |
|
138
|
+
| | initial.fee | Amount of fee on initial cost. |
|
139
|
+
| | initial.tax | Amount of tax for initial.fee. |
|
140
|
+
| invoice | | Carbon copy of Invoice attributes. |
|
141
|
+
| | id | |
|
142
|
+
| | contract_id | |
|
143
|
+
| | issue_date | |
|
144
|
+
| | due_date | |
|
145
|
+
| customer | | Carbon copy of Invoice customer except 'to'. |
|
146
|
+
| items | | Carbon copy of Invoice items. |
|
147
|
+
| subtotal | | Carbon copy of Invoice subtotal. |
|
148
|
+
| status | | Array of status with timestamp. |
|
149
|
+
|
150
|
+
|
27
151
|
## Development
|
28
152
|
|
29
153
|
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 +156,4 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
32
156
|
|
33
157
|
## Contributing
|
34
158
|
|
35
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
159
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/chumaltd/luca .
|
data/exe/luca-deal
CHANGED
@@ -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.
|
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
|
data/lib/luca_deal.rb
CHANGED
@@ -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
|
data/lib/luca_deal/contract.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'luca_deal/version'
|
2
4
|
|
3
5
|
require 'yaml'
|
@@ -13,35 +15,55 @@ module LucaDeal
|
|
13
15
|
@pjdir = Pathname(Dir.pwd)
|
14
16
|
end
|
15
17
|
|
18
|
+
# returns active contracts on specified date.
|
19
|
+
#
|
20
|
+
def self.asof(year, month, day)
|
21
|
+
return enum_for(:asof, year, month, day) unless block_given?
|
22
|
+
|
23
|
+
new("#{year}-#{month}-#{day}").active do |contract|
|
24
|
+
yield contract
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
16
28
|
#
|
17
29
|
# collect active contracts
|
18
30
|
#
|
19
31
|
def active
|
32
|
+
return enum_for(:active) unless block_given?
|
33
|
+
|
20
34
|
self.class.all do |data|
|
21
|
-
|
22
|
-
contract['items'] = contract['items'].map { |item| parse_current(item) }
|
23
|
-
next if !self.class.active_period?(contract)
|
35
|
+
next if !active_period?(data.dig('terms'))
|
24
36
|
|
25
|
-
|
37
|
+
contract = parse_current(data)
|
38
|
+
contract['items'] = contract['items']&.map { |item| parse_current(item) }
|
39
|
+
# TODO: handle sales_fee rate change
|
40
|
+
contract['rate'] = contract['rate']
|
41
|
+
yield contract.compact
|
26
42
|
end
|
27
43
|
end
|
28
44
|
|
29
|
-
def generate!(customer_id, mode =
|
45
|
+
def generate!(customer_id, mode = 'subscription')
|
30
46
|
LucaDeal::Customer.find(customer_id) do |customer|
|
31
47
|
current_customer = parse_current(customer)
|
32
|
-
obj = { 'customer_id' => current_customer['id'], 'customer_name' => current_customer['name'] }
|
33
|
-
obj['terms'] = { 'effective' => @date }
|
34
48
|
if mode == 'sales_fee'
|
35
|
-
obj
|
49
|
+
obj = salesfee_template
|
36
50
|
else
|
37
|
-
obj
|
51
|
+
obj = monthly_template
|
38
52
|
end
|
53
|
+
obj.merge!({ 'customer_id' => current_customer['id'], 'customer_name' => current_customer['name'] })
|
54
|
+
obj['terms'] ||= {}
|
55
|
+
obj['terms']['effective'] = @date
|
39
56
|
self.class.create(obj)
|
40
57
|
end
|
41
58
|
end
|
42
59
|
|
43
|
-
def
|
44
|
-
|
60
|
+
def active_period?(dat)
|
61
|
+
unless dat.dig('defunct').nil?
|
62
|
+
defunct = dat.dig('defunct').respond_to?(:year) ? dat.dig('defunct') : Date.parse(dat.dig('defunct'))
|
63
|
+
return false if @date > defunct
|
64
|
+
end
|
65
|
+
effective = dat.dig('effective').respond_to?(:year) ? dat.dig('effective') : Date.parse(dat.dig('effective'))
|
66
|
+
@date >= effective
|
45
67
|
end
|
46
68
|
|
47
69
|
private
|
data/lib/luca_deal/customer.rb
CHANGED
@@ -21,17 +21,20 @@ module LucaDeal
|
|
21
21
|
YAML.dump(list).tap { |l| puts l }
|
22
22
|
end
|
23
23
|
|
24
|
-
def
|
25
|
-
|
24
|
+
def self.create(obj)
|
25
|
+
raise ':name is required' if obj[:name].nil?
|
26
|
+
|
27
|
+
contacts = obj[:contact]&.map { |c| { 'mail' => c[:mail] } }&.compact
|
28
|
+
contacts ||= [{
|
26
29
|
'mail' => '_MAIL_ADDRESS_FOR_CONTACT_'
|
30
|
+
}]
|
31
|
+
h = {
|
32
|
+
'name' => obj[:name],
|
33
|
+
'address' => obj[:address] || '_CUSTOMER_ADDRESS_FOR_INVOICE_',
|
34
|
+
'address2' => obj[:address2] || '_CUSTOMER_ADDRESS_FOR_INVOICE_',
|
35
|
+
'contacts' => contacts
|
27
36
|
}
|
28
|
-
|
29
|
-
'name' => name,
|
30
|
-
'address' => '_CUSTOMER_ADDRESS_FOR_INVOICE_',
|
31
|
-
'address2' => '_CUSTOMER_ADDRESS_FOR_INVOICE_',
|
32
|
-
'contacts' => [contact]
|
33
|
-
}
|
34
|
-
self.class.create(obj)
|
37
|
+
super(h)
|
35
38
|
end
|
36
39
|
end
|
37
40
|
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_record!(fee, @date, 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
|
data/lib/luca_deal/invoice.rb
CHANGED
@@ -58,7 +58,6 @@ module LucaDeal
|
|
58
58
|
mail
|
59
59
|
end
|
60
60
|
|
61
|
-
#
|
62
61
|
# Output seriarized invoice data to stdout.
|
63
62
|
# Returns previous N months on multiple count
|
64
63
|
#
|
@@ -113,20 +112,23 @@ module LucaDeal
|
|
113
112
|
invoice['customer'] = get_customer(contract.dig('customer_id'))
|
114
113
|
invoice['due_date'] = due_date(@date)
|
115
114
|
invoice['issue_date'] = @date
|
115
|
+
invoice['sales_fee'] = contract.dig('sales_fee')
|
116
116
|
invoice['items'] = contract.dig('items').map do |item|
|
117
|
+
next if item.dig('type') == 'initial' && subsequent_month?(contract.dig('terms', 'effective'))
|
118
|
+
|
117
119
|
{}.tap do |h|
|
118
120
|
h['name'] = item.dig('name')
|
119
121
|
h['price'] = item.dig('price')
|
120
|
-
h['qty'] = item.dig('qty')
|
122
|
+
h['qty'] = item.dig('qty') || 1
|
123
|
+
h['type'] = item.dig('type') if item.dig('type')
|
121
124
|
end
|
122
|
-
end
|
125
|
+
end.compact
|
123
126
|
invoice['subtotal'] = subtotal(invoice['items'])
|
124
127
|
.map { |k, v| v.tap { |dat| dat['rate'] = k } }
|
125
128
|
gen_invoice!(invoice)
|
126
129
|
end
|
127
130
|
end
|
128
131
|
|
129
|
-
#
|
130
132
|
# set variables for ERB template
|
131
133
|
#
|
132
134
|
def invoice_vars(invoice_dat)
|
@@ -172,7 +174,6 @@ module LucaDeal
|
|
172
174
|
__dir__
|
173
175
|
end
|
174
176
|
|
175
|
-
#
|
176
177
|
# load user company profile from config.
|
177
178
|
#
|
178
179
|
def set_company
|
@@ -183,7 +184,6 @@ module LucaDeal
|
|
183
184
|
end
|
184
185
|
end
|
185
186
|
|
186
|
-
#
|
187
187
|
# calc items & tax amount by tax category
|
188
188
|
#
|
189
189
|
def subtotal(items)
|
@@ -199,7 +199,6 @@ module LucaDeal
|
|
199
199
|
end
|
200
200
|
end
|
201
201
|
|
202
|
-
#
|
203
202
|
# load Tax Rate from config.
|
204
203
|
#
|
205
204
|
def load_tax_rate(name)
|
@@ -218,5 +217,10 @@ module LucaDeal
|
|
218
217
|
end
|
219
218
|
false
|
220
219
|
end
|
220
|
+
|
221
|
+
def subsequent_month?(effective_date)
|
222
|
+
effective_date = Date.parse(effective_date) unless effective_date.respond_to? :year
|
223
|
+
effective_date.year != @date.year || effective_date.month != @date.month
|
224
|
+
end
|
221
225
|
end
|
222
226
|
end
|
@@ -0,0 +1,42 @@
|
|
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
|
+
|
14
|
+
def list_name
|
15
|
+
list = self.class.all.map { |dat| parse_current(dat) }
|
16
|
+
YAML.dump(list).tap { |l| puts l }
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.create(obj)
|
20
|
+
raise ':name is required' if obj[:name].nil?
|
21
|
+
|
22
|
+
items = [{
|
23
|
+
'name' => obj[:name],
|
24
|
+
'price' => obj[:price] || 0,
|
25
|
+
'qty' => obj[:qty] || 1
|
26
|
+
}]
|
27
|
+
if obj[:initial]
|
28
|
+
items << {
|
29
|
+
'name' => obj.dig(:initial, :name),
|
30
|
+
'price' => obj.dig(:initial, :price) || 0,
|
31
|
+
'qty' => obj.dig(:initial, :qty) || 1,
|
32
|
+
'type' => 'initial'
|
33
|
+
}
|
34
|
+
end
|
35
|
+
h = {
|
36
|
+
'name' => obj[:name],
|
37
|
+
'items' => items
|
38
|
+
}
|
39
|
+
super(h)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/luca_deal/version.rb
CHANGED
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.
|
4
|
+
version: 0.2.13
|
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-11-
|
11
|
+
date: 2020-11-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: lucarecord
|
@@ -83,7 +83,9 @@ files:
|
|
83
83
|
- lib/luca_deal.rb
|
84
84
|
- lib/luca_deal/contract.rb
|
85
85
|
- lib/luca_deal/customer.rb
|
86
|
+
- lib/luca_deal/fee.rb
|
86
87
|
- lib/luca_deal/invoice.rb
|
88
|
+
- lib/luca_deal/product.rb
|
87
89
|
- lib/luca_deal/setup.rb
|
88
90
|
- lib/luca_deal/templates/.keep
|
89
91
|
- lib/luca_deal/templates/config.yml
|