lucadeal 0.2.9 → 0.2.13
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 +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
|