piggybak 0.5.5 → 0.6.0
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.
- data/README.md +32 -25
- data/VERSION +1 -1
- data/app/assets/javascripts/piggybak.js +11 -1
- data/app/assets/javascripts/piggybak.states.js +6 -5
- data/app/controllers/piggybak/orders_controller.rb +14 -22
- data/app/models/piggybak/address.rb +4 -1
- data/app/models/piggybak/adjustment.rb +1 -25
- data/app/models/piggybak/cart.rb +18 -17
- data/app/models/piggybak/line_item.rb +106 -19
- data/app/models/piggybak/order.rb +94 -108
- data/app/models/piggybak/payment.rb +25 -27
- data/app/models/piggybak/payment_method.rb +3 -1
- data/app/models/piggybak/payment_method_value.rb +3 -1
- data/app/models/piggybak/{variant.rb → sellable.rb} +6 -4
- data/app/models/piggybak/shipment.rb +4 -10
- data/app/models/piggybak/shipping_calculator/flat_rate.rb +4 -0
- data/app/models/piggybak/shipping_calculator/free.rb +4 -0
- data/app/models/piggybak/shipping_calculator/range.rb +4 -0
- data/app/models/piggybak/shipping_method.rb +1 -1
- data/app/models/piggybak/tax_method.rb +1 -1
- data/app/views/piggybak/cart/_form.html.erb +7 -7
- data/app/views/piggybak/cart/_items.html.erb +14 -5
- data/app/views/piggybak/notifier/order_notification.text.erb +10 -2
- data/app/views/piggybak/orders/_details.html.erb +14 -5
- data/app/views/piggybak/orders/_google_analytics.html.erb +3 -3
- data/app/views/piggybak/orders/download.text.erb +6 -6
- data/app/views/piggybak/orders/submit.html.erb +55 -49
- data/app/views/rails_admin/main/_location_select.html.haml +3 -3
- data/app/views/rails_admin/main/_order_details.html.erb +12 -24
- data/app/views/rails_admin/main/_polymorphic_nested.html.haml +29 -0
- data/bin/piggybak +12 -0
- data/config/routes.rb +0 -2
- data/db/migrate/20121008160425_rename_variants_to_sellables.rb +11 -0
- data/db/migrate/20121008175144_line_item_rearchitecture.rb +96 -0
- data/lib/acts_as_sellable.rb +21 -0
- data/lib/formatted_changes.rb +2 -2
- data/lib/piggybak.rb +80 -126
- data/lib/piggybak/cli.rb +81 -0
- data/lib/piggybak/config.rb +21 -0
- data/piggybak.gemspec +10 -7
- data/spec/dummy_app/app/models/image.rb +1 -1
- data/spec/factories.rb +1 -1
- metadata +52 -49
- data/app/controllers/piggybak/payments_controller.rb +0 -14
- data/app/views/rails_admin/main/_order_notes.html.erb +0 -1
- data/app/views/rails_admin/main/_payment_refund.html.haml +0 -6
- data/lib/acts_as_variant.rb +0 -15
data/README.md
CHANGED
@@ -11,46 +11,47 @@ Modular / mountable ecommerce gem. Features:
|
|
11
11
|
|
12
12
|
* Fully defined backend RailsAdmin interface for adding orders on the backend
|
13
13
|
|
14
|
+
|
15
|
+
Announcements
|
16
|
+
========
|
17
|
+
|
18
|
+
* Variants were recently changed to sellables, to provide the opportunity for advanced variant support via an extension.
|
19
|
+
|
20
|
+
* Significant recent rearchitecture has been applied to the order line items. Stay tuned for the documentation.
|
21
|
+
|
22
|
+
* Review the new installation process below.
|
23
|
+
|
24
|
+
|
14
25
|
Installation
|
15
26
|
========
|
16
27
|
|
17
|
-
* First
|
28
|
+
* First create a new rails project:
|
29
|
+
rails new webstore
|
30
|
+
|
31
|
+
* Config your database.yml and create the databases
|
32
|
+
|
33
|
+
* Add to Gemfile:
|
18
34
|
|
19
35
|
gem "piggybak"
|
20
|
-
gem "piggybak", '0.4.19'
|
21
|
-
gem "piggybak", :git => "git://github.com/stephskardal/piggybak.git"
|
22
36
|
|
23
|
-
* Next, run
|
37
|
+
* Next, run bundle install:
|
24
38
|
|
25
|
-
|
39
|
+
bundle install
|
26
40
|
|
27
|
-
* Next, run
|
41
|
+
* Next, run the piggybak install command:
|
28
42
|
|
29
|
-
|
43
|
+
piggybak install
|
30
44
|
|
31
|
-
|
45
|
+
(NOTE: If you run into an error saying that piggybak gem is missing, use bundle exec piggybak install)
|
32
46
|
|
33
|
-
|
34
|
-
|
35
|
-
* Add acts_as_variant to any model that will become a sellable item.
|
47
|
+
* Piggybak is now installed and ready to be added to whatever model class will be sold.
|
36
48
|
|
37
49
|
class Product < ActiveRecord::Base
|
38
|
-
|
50
|
+
acts_as_sellable
|
39
51
|
end
|
40
52
|
|
41
|
-
*
|
42
|
-
|
43
|
-
//= require jquery_ujs
|
44
|
-
|
45
|
-
* You must add the following to your application layout:
|
46
|
-
|
47
|
-
<% if "#{params[:controller]}##{params[:action]}" == "piggybak/orders#submit" -%>
|
48
|
-
<%= javascript_include_tag "piggybak-application" %>
|
49
|
-
<% end -%>
|
53
|
+
* Piggybak checkout is located at /checkout
|
50
54
|
|
51
|
-
* And you must add this to your production configuration, in order for this asset to be precompiled (and in some cases, ensure that it is served via SSL):
|
52
|
-
|
53
|
-
config.assets.precompile += %w( piggybak-application.js )
|
54
55
|
|
55
56
|
More Details
|
56
57
|
========
|
@@ -62,7 +63,13 @@ Visit the project website [here][project-website] to see more documentation and
|
|
62
63
|
TODO
|
63
64
|
========
|
64
65
|
|
65
|
-
|
66
|
+
* Ensure that changes in nested addresses are recorded on order notes.
|
67
|
+
|
68
|
+
* Add admin side validation to limit 1 payment at a time
|
69
|
+
|
70
|
+
* Add/check validation to ensure sufficient inventory
|
71
|
+
|
72
|
+
* Add copy from billing above shipping address section button
|
66
73
|
|
67
74
|
Copyright
|
68
75
|
========
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.6.0
|
@@ -4,7 +4,8 @@ var page_load = 1;
|
|
4
4
|
var shipping_field;
|
5
5
|
|
6
6
|
$(function() {
|
7
|
-
|
7
|
+
piggybak.prevent_double_click();
|
8
|
+
shipping_field = $('#piggybak_order_line_items_attributes_0_shipment_attributes_shipping_method_id');
|
8
9
|
shipping_els = $('#piggybak_order_shipping_address_attributes_state_id,#piggybak_order_shipping_address_attributes_country_id,#piggybak_order_shipping_address_attributes_zip');
|
9
10
|
piggybak.initialize_listeners();
|
10
11
|
piggybak.update_shipping_options($('#piggybak_order_shipping_address_attributes_state_id'), function() {
|
@@ -14,6 +15,12 @@ $(function() {
|
|
14
15
|
});
|
15
16
|
|
16
17
|
var piggybak = {
|
18
|
+
prevent_double_click: function() {
|
19
|
+
$('#new_piggybak_order').find('input:submit').removeAttr('disabled');
|
20
|
+
$('#new_piggybak_order').submit(function() {
|
21
|
+
$(this).find('input:submit').attr('disabled', 'disabled');
|
22
|
+
});
|
23
|
+
},
|
17
24
|
initialize_listeners: function() {
|
18
25
|
shipping_els.live('change', function() {
|
19
26
|
piggybak.update_shipping_options($(this));
|
@@ -117,6 +124,9 @@ var piggybak = {
|
|
117
124
|
}
|
118
125
|
$('#shipping_total').html('$' + shipping_total.toFixed(2));
|
119
126
|
var order_total = subtotal + tax_total + shipping_total;
|
127
|
+
$.each($('.extra_totals'), function(i, el) {
|
128
|
+
order_total += parseFloat($(el).html().replace(/\$/, ''));
|
129
|
+
});
|
120
130
|
$('#order_total').html('$' + order_total.toFixed(2));
|
121
131
|
},
|
122
132
|
retrieve_shipping_data: function() {
|
@@ -1,10 +1,5 @@
|
|
1
1
|
var geodata;
|
2
2
|
|
3
|
-
$(function() {
|
4
|
-
piggybak_states.populate_geodata();
|
5
|
-
piggybak_states.initialize_listeners();
|
6
|
-
});
|
7
|
-
|
8
3
|
var piggybak_states = {
|
9
4
|
initialize_listeners: function() {
|
10
5
|
$('#piggybak_order_shipping_address_attributes_country_id').change(function() {
|
@@ -53,3 +48,9 @@ var piggybak_states = {
|
|
53
48
|
return;
|
54
49
|
}
|
55
50
|
};
|
51
|
+
|
52
|
+
$(function() {
|
53
|
+
piggybak_states.populate_geodata();
|
54
|
+
piggybak_states.initialize_listeners();
|
55
|
+
});
|
56
|
+
|
@@ -10,12 +10,14 @@ module Piggybak
|
|
10
10
|
begin
|
11
11
|
ActiveRecord::Base.transaction do
|
12
12
|
@order = Piggybak::Order.new(params[:piggybak_order])
|
13
|
+
@order.create_payment_shipment
|
13
14
|
|
14
15
|
if Piggybak.config.logging
|
15
|
-
|
16
|
-
clean_params
|
17
|
-
clean_params["payments_attributes"]["0"]["
|
18
|
-
|
16
|
+
# TODO: Reimplement on correctly filtered params
|
17
|
+
#clean_params = params[:piggybak_order].clone
|
18
|
+
#clean_params["payments_attributes"]["0"]["number"] = clean_params["payments_attributes"]["0"]["number"].mask_cc_number
|
19
|
+
#clean_params["payments_attributes"]["0"]["verification_value"] = clean_params["payments_attributes"]["0"]["verification_value"].mask_csv
|
20
|
+
#logger.info "#{request.remote_ip}:#{Time.now.strftime("%Y-%m-%d %H:%M")} Order received with params #{clean_params.inspect}"
|
19
21
|
end
|
20
22
|
@order.initialize_user(current_user, true)
|
21
23
|
|
@@ -28,6 +30,7 @@ module Piggybak
|
|
28
30
|
end
|
29
31
|
|
30
32
|
if @order.save
|
33
|
+
# TODO: Imporant: figure out how to have notifications not trigger rollback here. Instead log failed order notification sent.
|
31
34
|
Piggybak::Notifier.order_notification(@order).deliver
|
32
35
|
|
33
36
|
if Piggybak.config.logging
|
@@ -52,8 +55,9 @@ module Piggybak
|
|
52
55
|
@order.errors[:base] << "Your order could not go through. Please try again."
|
53
56
|
end
|
54
57
|
end
|
55
|
-
|
58
|
+
else
|
56
59
|
@order = Piggybak::Order.new
|
60
|
+
@order.create_payment_shipment
|
57
61
|
@order.initialize_user(current_user, false)
|
58
62
|
end
|
59
63
|
end
|
@@ -95,18 +99,6 @@ module Piggybak
|
|
95
99
|
redirect_to rails_admin.edit_path('Piggybak::Order', order.id)
|
96
100
|
end
|
97
101
|
|
98
|
-
def restore
|
99
|
-
order = Order.find(params[:id])
|
100
|
-
order.recorded_changer = current_user.id
|
101
|
-
|
102
|
-
if can?(:restore, order)
|
103
|
-
order.status = "new"
|
104
|
-
order.save
|
105
|
-
end
|
106
|
-
|
107
|
-
redirect_to rails_admin.edit_path('Piggybak::Order', order.id)
|
108
|
-
end
|
109
|
-
|
110
102
|
def cancel
|
111
103
|
order = Order.find(params[:id])
|
112
104
|
|
@@ -115,18 +107,18 @@ module Piggybak
|
|
115
107
|
order.disable_order_notes = true
|
116
108
|
|
117
109
|
order.line_items.each do |line_item|
|
118
|
-
line_item.
|
119
|
-
|
120
|
-
|
121
|
-
shipment.mark_for_destruction
|
110
|
+
if line_item.line_item_type != "payment"
|
111
|
+
line_item.mark_for_destruction
|
112
|
+
end
|
122
113
|
end
|
123
|
-
order.update_attribute(:tax_charge, 0.00)
|
124
114
|
order.update_attribute(:total, 0.00)
|
125
115
|
order.update_attribute(:to_be_cancelled, true)
|
126
116
|
|
127
117
|
OrderNote.create(:order_id => order.id, :note => "Order set to cancelled. Line items, shipments, tax removed.", :user_id => current_user.id)
|
128
118
|
|
129
119
|
flash[:notice] = "Order #{order.id} set to cancelled. Order is now in unbalanced state."
|
120
|
+
else
|
121
|
+
flash[:error] = "You do not have permission to cancel this order."
|
130
122
|
end
|
131
123
|
|
132
124
|
redirect_to rails_admin.edit_path('Piggybak::Order', order.id)
|
@@ -15,7 +15,10 @@ module Piggybak
|
|
15
15
|
|
16
16
|
after_initialize :set_default_country
|
17
17
|
after_save :document_address_changes
|
18
|
-
|
18
|
+
|
19
|
+
attr_accessible :firstname, :lastname, :address1, :location,
|
20
|
+
:address2, :city, :state_id, :zip, :country_id
|
21
|
+
|
19
22
|
def set_default_country
|
20
23
|
self.country ||= Country.find_by_abbr(Piggybak.config.default_country)
|
21
24
|
end
|
@@ -1,29 +1,5 @@
|
|
1
1
|
module Piggybak
|
2
2
|
class Adjustment < ActiveRecord::Base
|
3
|
-
|
4
|
-
belongs_to :source, :polymorphic => true
|
5
|
-
attr_accessor :user_id
|
6
|
-
acts_as_changer
|
7
|
-
|
8
|
-
validates_presence_of :order_id, :total
|
9
|
-
validates_numericality_of :total
|
10
|
-
validates_presence_of :source
|
11
|
-
|
12
|
-
before_validation :set_source
|
13
|
-
|
14
|
-
def set_source
|
15
|
-
if self.source.nil? && self.user_id.present?
|
16
|
-
self.source = User.find(self.user_id)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def admin_label
|
21
|
-
if !self.new_record?
|
22
|
-
return "Adjustment ##{self.id} (#{self.created_at.strftime("%m-%d-%Y")}): " +
|
23
|
-
"$#{"%.2f" % self.total}"
|
24
|
-
else
|
25
|
-
return ""
|
26
|
-
end
|
27
|
-
end
|
3
|
+
#TODO: Note this is deprecated after 0.5.5
|
28
4
|
end
|
29
5
|
end
|
data/app/models/piggybak/cart.rb
CHANGED
@@ -4,18 +4,19 @@ module Piggybak
|
|
4
4
|
attr_accessor :total
|
5
5
|
attr_accessor :errors
|
6
6
|
attr_accessor :extra_data
|
7
|
+
alias :subtotal :total
|
7
8
|
|
8
9
|
def initialize(cookie='')
|
9
10
|
self.items = []
|
10
11
|
self.errors = []
|
11
12
|
cookie ||= ''
|
12
13
|
cookie.split(';').each do |item|
|
13
|
-
|
14
|
-
if
|
15
|
-
self.items << { :
|
14
|
+
item_sellable = Piggybak::Sellable.find_by_id(item.split(':')[0])
|
15
|
+
if item_sellable.present?
|
16
|
+
self.items << { :sellable => item_sellable, :quantity => (item.split(':')[1]).to_i }
|
16
17
|
end
|
17
18
|
end
|
18
|
-
self.total = self.items.sum { |item| item[:quantity]*item[:
|
19
|
+
self.total = self.items.sum { |item| item[:quantity]*item[:sellable].price }
|
19
20
|
|
20
21
|
self.extra_data = {}
|
21
22
|
end
|
@@ -38,14 +39,14 @@ module Piggybak
|
|
38
39
|
|
39
40
|
def self.add(cookie, params)
|
40
41
|
cart = to_hash(cookie)
|
41
|
-
cart["#{params[:
|
42
|
-
cart["#{params[:
|
42
|
+
cart["#{params[:sellable_id]}"] ||= 0
|
43
|
+
cart["#{params[:sellable_id]}"] += params[:quantity].to_i
|
43
44
|
to_string(cart)
|
44
45
|
end
|
45
46
|
|
46
|
-
def self.remove(cookie,
|
47
|
+
def self.remove(cookie, sellable_id)
|
47
48
|
cart = to_hash(cookie)
|
48
|
-
cart[
|
49
|
+
cart[sellable_id] = 0
|
49
50
|
to_string(cart)
|
50
51
|
end
|
51
52
|
|
@@ -58,7 +59,7 @@ module Piggybak
|
|
58
59
|
def to_cookie
|
59
60
|
cookie = ''
|
60
61
|
self.items.each do |item|
|
61
|
-
cookie += "#{item[:
|
62
|
+
cookie += "#{item[:sellable].id.to_s}:#{item[:quantity].to_s};" if item[:quantity].to_i > 0
|
62
63
|
end
|
63
64
|
cookie
|
64
65
|
end
|
@@ -67,20 +68,20 @@ module Piggybak
|
|
67
68
|
self.errors = []
|
68
69
|
new_items = []
|
69
70
|
self.items.each do |item|
|
70
|
-
if !item[:
|
71
|
-
self.errors << ["Sorry, #{item[:
|
72
|
-
elsif item[:
|
71
|
+
if !item[:sellable].active
|
72
|
+
self.errors << ["Sorry, #{item[:sellable].description} is no longer for sale"]
|
73
|
+
elsif item[:sellable].unlimited_inventory || item[:sellable].quantity >= item[:quantity]
|
73
74
|
new_items << item
|
74
|
-
elsif item[:
|
75
|
-
self.errors << ["Sorry, #{item[:
|
75
|
+
elsif item[:sellable].quantity == 0
|
76
|
+
self.errors << ["Sorry, #{item[:sellable].description} is no longer available"]
|
76
77
|
else
|
77
|
-
self.errors << ["Sorry, only #{item[:
|
78
|
-
item[:quantity] = item[:
|
78
|
+
self.errors << ["Sorry, only #{item[:sellable].quantity} available for #{item[:sellable].description}"]
|
79
|
+
item[:quantity] = item[:sellable].quantity
|
79
80
|
new_items << item if item[:quantity] > 0
|
80
81
|
end
|
81
82
|
end
|
82
83
|
self.items = new_items
|
83
|
-
self.total = self.items.sum { |item| item[:quantity]*item[:
|
84
|
+
self.total = self.items.sum { |item| item[:quantity]*item[:sellable].price }
|
84
85
|
end
|
85
86
|
|
86
87
|
def set_extra_data(form_params)
|
@@ -2,39 +2,126 @@ module Piggybak
|
|
2
2
|
class LineItem < ActiveRecord::Base
|
3
3
|
belongs_to :order
|
4
4
|
acts_as_changer
|
5
|
-
belongs_to :
|
6
|
-
|
7
|
-
validates_presence_of :
|
8
|
-
validates_presence_of :total
|
9
|
-
validates_presence_of :price
|
10
|
-
validates_presence_of :description
|
11
|
-
validates_presence_of :quantity
|
5
|
+
belongs_to :sellable
|
6
|
+
|
7
|
+
validates_presence_of :price, :description, :quantity
|
12
8
|
validates_numericality_of :quantity, :only_integer => true, :greater_than_or_equal_to => 0
|
13
9
|
|
14
|
-
after_create :decrease_inventory, :if => Proc.new { |line_item| !line_item.
|
15
|
-
after_destroy :increase_inventory, :if => Proc.new { |line_item| !line_item.
|
16
|
-
after_update :update_inventory, :if => Proc.new { |line_item| !line_item.
|
17
|
-
|
10
|
+
after_create :decrease_inventory, :if => Proc.new { |line_item| line_item.line_item_type == 'sellable' && !line_item.sellable.unlimited_inventory }
|
11
|
+
after_destroy :increase_inventory, :if => Proc.new { |line_item| line_item.line_item_type == 'sellable' && !line_item.sellable.unlimited_inventory }
|
12
|
+
after_update :update_inventory, :if => Proc.new { |line_item| line_item.line_item_type == 'sellable' && !line_item.sellable.unlimited_inventory }
|
13
|
+
|
14
|
+
attr_accessible :sellable_id, :price, :unit_price, :description, :quantity, :line_item_type
|
15
|
+
|
16
|
+
after_initialize :initialize_line_item
|
17
|
+
before_validation :preprocess
|
18
|
+
before_destroy :destroy_associated_item
|
19
|
+
|
20
|
+
def initialize_line_item
|
21
|
+
self.quantity ||= 1
|
22
|
+
self.price ||= 0
|
23
|
+
end
|
24
|
+
|
25
|
+
def preprocess
|
26
|
+
# TODO: Investigate if this is unnecessary if you use reject_if on accepts_nested_attributes_for
|
27
|
+
Piggybak.config.line_item_types.each do |k, v|
|
28
|
+
if v.has_key?(:nested_attrs) && k != self.line_item_type.to_sym
|
29
|
+
self.send("#{k}=", nil)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
method = "preprocess_#{self.line_item_type}"
|
34
|
+
self.send(method) if self.respond_to?(method)
|
35
|
+
end
|
36
|
+
|
37
|
+
def preprocess_sellable
|
38
|
+
sellable = Piggybak::Sellable.find(self.sellable_id)
|
39
|
+
|
40
|
+
return if sellable.nil?
|
41
|
+
|
42
|
+
self.description = sellable.description
|
43
|
+
self.unit_price = sellable.price
|
44
|
+
self.price = self.unit_price*self.quantity.to_i
|
45
|
+
end
|
46
|
+
|
47
|
+
def preprocess_shipment
|
48
|
+
if !self._destroy
|
49
|
+
if (self.new_record? || self.shipment.status != 'shipped') && self.shipment && self.shipment.shipping_method
|
50
|
+
calculator = self.shipment.shipping_method.klass.constantize
|
51
|
+
self.price = calculator.rate(self.shipment.shipping_method, self)
|
52
|
+
self.price = ((self.price*100).to_i).to_f/100
|
53
|
+
self.description = self.shipment.shipping_method.description
|
54
|
+
end
|
55
|
+
if self.shipment.nil? || self.shipment.shipping_method.nil?
|
56
|
+
self.price = 0.00
|
57
|
+
self.description = "Shipping"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def preprocess_payment
|
63
|
+
if self.new_record?
|
64
|
+
self.payment.payment_method_id ||= Piggybak::PaymentMethod.find_by_active(true).id if self.payment
|
65
|
+
self.description = "Payment"
|
66
|
+
self.price = 0
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def postprocess_payment
|
71
|
+
return true if !self.new_record?
|
72
|
+
|
73
|
+
if self.payment.process(self.order)
|
74
|
+
self.price = -1*self.order.total_due
|
75
|
+
self.order.total_due = 0
|
76
|
+
return true
|
77
|
+
else
|
78
|
+
return false
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Dependent destroy is not working as expected, so this is in place
|
83
|
+
def destroy_associated_item
|
84
|
+
line_item_type_sym = self.line_item_type.to_sym
|
85
|
+
if Piggybak.config.line_item_types[line_item_type_sym].has_key?(:nested_attrs)
|
86
|
+
if Piggybak.config.line_item_types[line_item_type_sym][:nested_attrs]
|
87
|
+
b = self.send("#{line_item_type_sym}")
|
88
|
+
b.destroy if b.present?
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.line_item_type_select
|
94
|
+
Piggybak.config.line_item_types.select { |k, v| v[:visible] }.collect { |k, v| [k.to_s.humanize.titleize, k] }
|
95
|
+
end
|
96
|
+
|
97
|
+
def sellable_id_enum
|
98
|
+
::Piggybak::Sellable.all.collect { |s| ["#{s.description}: $#{s.price}", s.id ] }
|
99
|
+
end
|
100
|
+
|
18
101
|
def admin_label
|
19
|
-
|
102
|
+
if self.line_item_type == 'sellable'
|
103
|
+
"#{self.quantity} x #{self.description} ($#{sprintf("%.2f", self.unit_price)}): $#{sprintf("%.2f", self.price)}".gsub('"', '"')
|
104
|
+
else
|
105
|
+
"#{self.description}: $#{sprintf("%.2f", self.price)}".gsub('"', '"')
|
106
|
+
end
|
20
107
|
end
|
21
108
|
|
22
109
|
def decrease_inventory
|
23
|
-
self.
|
110
|
+
self.sellable.update_inventory(-1 * self.quantity)
|
24
111
|
end
|
25
112
|
|
26
113
|
def increase_inventory
|
27
|
-
self.
|
114
|
+
self.sellable.update_inventory(self.quantity)
|
28
115
|
end
|
29
116
|
|
30
117
|
def update_inventory
|
31
|
-
if self.
|
32
|
-
|
33
|
-
|
34
|
-
self.
|
118
|
+
if self.sellable_id != self.sellable_id_was
|
119
|
+
old_sellable = Sellable.find(self.sellable_id_was)
|
120
|
+
old_sellable.update_inventory(self.quantity_was)
|
121
|
+
self.sellable.update_inventory(-1*self.quantity)
|
35
122
|
else
|
36
123
|
quantity_diff = self.quantity_was - self.quantity
|
37
|
-
self.
|
124
|
+
self.sellable.update_inventory(quantity_diff)
|
38
125
|
end
|
39
126
|
end
|
40
127
|
end
|