-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathitem.rb
94 lines (74 loc) · 2.6 KB
/
item.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
class Item
attr_reader :number, :name, :description
attr_reader :price_cents, :unit, :tax_flag
attr_reader :modifiers
attr_accessor :receipt
def initialize(number:, name:, price_cents:, description:, unit:, tax_flag:)
@number = number.to_i
@name = name
@price_cents = price_cents # Price before modifiers (discounts) and tax
@description = description
@unit = unit
@tax_flag = tax_flag
@modifiers = [] # I've only seen one discount per item, but I'm not sure if that's always the case; thus the array
@receipt = nil
end
def pretty_name
product&.name || name.titleize
end
def image_url
product&.image_url
end
def product
product = Product.new(@number)
return nil if product.not_found?
product
end
# Price after discounts and tax
def total_price_cents
modified_price_cents + tax_cents
end
# Tax amount cents
def tax_cents
tax_calculator.calculate_tax_cents(self)
end
# Price after discounts/fees/additional taxes, before tax
def modified_price_cents
@price_cents + total_modified_cents
end
# Total modified for this item (negative number)
def total_modified_cents
@modifiers.sum(&:amount_cents)
end
# Total modified, only including discounts (excluding fees/additional taxes)
def total_discounted_cents
@modifiers.filter do |modifier|
modifier.amount_cents.negative?
end.sum(&:amount_cents)
end
%w[total_price modified_price price tax total_modified total_discounted].each do |method_name|
define_method method_name do
send("#{method_name}_cents") / 100.0
end
# Define methods for Unit
define_method "unit_#{method_name}_cents" do
# This doesn't get rounded because calculating per-unit price can result
# in partial cents; mainly when discounts are applied (buy 1, get 1 free).
# Buy 1, get 1 free appears at 2 units, 1 discount. (e.g. (9.99 + 9.99 - 9.99) / 2 = 4.995)
send("#{method_name}_cents") / @unit.to_f
end
define_method "unit_#{method_name}" do
send("unit_#{method_name}_cents") / 100.0
end
end
def apply_modifier(modifier)
warn ArgumentError, "Modifier can not be applied to this item" if modifier.associated_item_number != @number
modifier.item = self
@modifiers << modifier
end
def tax_calculator
warn ArgumentError, "Item must be associated with a receipt/warehouse to create TaxCalculator" unless @receipt.present?
TaxCalculator.new(warehouse_number: @receipt.warehouse.number, tax_flag: @tax_flag, date: @receipt.datetime.to_date)
end
delegate :tax_rate, :taxable?, to: :tax_calculator
end