erp_orders 4.0.0 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/app/models/charge_line.rb +31 -13
  3. data/app/models/charge_type.rb +7 -0
  4. data/app/models/extensions/party.rb +13 -0
  5. data/app/models/order_line_item.rb +150 -14
  6. data/app/models/order_line_item_rel_type.rb +6 -0
  7. data/app/models/order_line_item_relationship.rb +8 -0
  8. data/app/models/order_txn.rb +314 -61
  9. data/app/models/sales_tax_line.rb +15 -0
  10. data/app/models/sales_tax_policy.rb +7 -0
  11. data/db/data_migrations/20141214150732_add_order_tracked_statues.rb +25 -0
  12. data/db/data_migrations/20150309004308_add_base_charge_types.rb +19 -0
  13. data/db/migrate/20080805000060_base_orders.rb +119 -111
  14. data/db/migrate/20150309003812_add_charge_type_to_charge_lines.rb +5 -0
  15. data/db/migrate/20150309004440_create_charge_types.rb +18 -0
  16. data/db/migrate/20150311160005_add_unit_price_to_order_line_items.rb +5 -0
  17. data/db/migrate/20150622151009_add_tax_policy.rb +42 -0
  18. data/db/migrate/20150622170438_update_taxation_for_orders.rb +58 -0
  19. data/db/migrate/20150624000721_add_internal_identifier_to_charge_type.rb +5 -0
  20. data/db/migrate/20160310163060_add_created_by_updated_by_to_erp_orders.rb +35 -0
  21. data/lib/erp_orders.rb +2 -0
  22. data/lib/erp_orders/engine.rb +0 -4
  23. data/lib/erp_orders/extensions/active_record/acts_as_order_line_item.rb +2 -1
  24. data/lib/erp_orders/extensions/active_record/acts_as_order_txn.rb +1 -1
  25. data/lib/erp_orders/taxation.rb +49 -0
  26. data/lib/erp_orders/version.rb +1 -1
  27. metadata +24 -15
  28. data/app/models/charge_line_payment_txn.rb +0 -7
  29. data/db/migrate/20130620203217_add_quantity_to_order_line_items.rb +0 -13
  30. data/db/migrate/20131005232344_update_order_line_pty_role_indexes.erp_orders.rb +0 -19
  31. data/db/migrate/20131005232611_remove_order_line_specific_rtype.rb +0 -32
  32. data/db/migrate/20140129200040_add_uom_to_order_line_item.rb +0 -13
  33. data/db/migrate/20140930152140_add_custom_fields_to_order_txn.rb +0 -12
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1e462b6d0534235ea385e6837474e1305e8be2f5
4
- data.tar.gz: 1d7127f89c3657cb616464755fc125924572908c
3
+ metadata.gz: 5b6867785c98bc211e0349e3c5a3c2d7139277ce
4
+ data.tar.gz: 10720ff3b69094fe0c7c2873eec1eec70c70dad5
5
5
  SHA512:
6
- metadata.gz: 97c4b54627004f27ff46faa7f4cc49472d28426c63e3191cc76872e87b97f0deb27cf6d848d092ee41d16a01fb983dcf41d1692a6565dcd1abd83dccbfc26358
7
- data.tar.gz: d7db617036bd2dac557a01ad6ed246608d466fc1ae7ef9fddc8e4be88cf4cc7131a1e1e3e3e5168d0483f15c856bde9b5045c7149aab561e6634b7987cd31a6d
6
+ metadata.gz: 9206b5e1533e05612c2e2fc3b5dd21da40bba895deae4b53ec422eba56815b50ce5484deb3f5cad050d00fb6aecf7f546a7838aaa5d6d3d0ecc22e5152e4e9e7
7
+ data.tar.gz: 75dcd09070cd56edb15ab308878f818b07681b0c21edc4df9d484c50c6a969b9caa103a6163a8533f9d81872593de9009dac17e7b085a0a55e459fe4b8311b59
@@ -1,23 +1,41 @@
1
+ # create_table :charge_lines do |t|
2
+ # t.string :sti_type
3
+ # t.references :money
4
+ # t.string :description #could be expanded to include type information, etc.
5
+ # t.string :external_identifier
6
+ # t.string :external_id_source
7
+ #
8
+ # #polymorphic
9
+ # t.references :charged_item, :polymorphic => true
10
+ #
11
+ # t.timestamps
12
+ # end
13
+ #
14
+ # add_index :charge_lines, [:charged_item_id, :charged_item_type], :name => 'charged_item_idx'
15
+
1
16
  class ChargeLine < ActiveRecord::Base
2
17
  attr_protected :created_at, :updated_at
3
18
 
19
+ tracks_created_by_updated_by
20
+
4
21
  belongs_to :charged_item, :polymorphic => true
5
- belongs_to :money
6
- has_many :charge_line_payment_txns, :dependent => :destroy
7
- has_many :financial_txns, :through => :charge_line_payment_txns, :source => :financial_txn,
8
- :conditions => ["charge_line_payment_txns.payment_txn_type = ?", 'FinancialTxn']
22
+ belongs_to :money, :dependent => :destroy
23
+ belongs_to :charge_type
9
24
 
10
- def payment_txns
11
- self.financial_txns
25
+ has_many :sales_tax_lines, as: :taxed_record, dependent: :destroy
26
+
27
+ def taxed?
28
+ self.charge_type.try(:taxable)
12
29
  end
13
30
 
14
- def add_payment_txn(payment_txn)
15
- charge_line_payment_txn = ChargeLinePaymentTxn.new
16
- charge_line_payment_txn.charge_line = self
17
- charge_line_payment_txn.payment_txn = payment_txn
18
- charge_line_payment_txn.save
19
- charge_line_payment_txns << charge_line_payment_txn
20
- self.save
31
+ # calculates tax and save to sales_tax
32
+ def calculate_tax(ctx={})
33
+ taxation = ErpOrders::Taxation.new
34
+
35
+ self.sales_tax = taxation.calculate_tax(self,
36
+ ctx.merge({
37
+ amount: money.amount
38
+ }))
21
39
  end
22
40
 
23
41
  end
@@ -0,0 +1,7 @@
1
+ class ChargeType < ActiveRecord::Base
2
+ attr_protected :created_at, :updated_at
3
+
4
+ acts_as_erp_type
5
+
6
+ has_many :charge_lines
7
+ end
@@ -1,3 +1,16 @@
1
1
  Party.class_eval do
2
2
  has_many :order_line_item_pty_roles
3
+
4
+ def orders(statuses=[])
5
+ statement = OrderTxn
6
+
7
+ unless statuses.empty?
8
+ statement = statement.with_current_status({'order_statuses' => statuses})
9
+ end
10
+
11
+ statement = statement.joins(:biz_txn_event => :biz_txn_party_roles)
12
+ .where(:biz_txn_party_roles => {:party_id => self.id})
13
+
14
+ statement
15
+ end
3
16
  end
@@ -1,34 +1,170 @@
1
+ # create_table :order_line_items do |t|
2
+ # t.integer :order_txn_id
3
+ # t.integer :order_line_item_type_id
4
+ # t.integer :product_offer_id
5
+ # t.string :product_offer_description
6
+ # t.integer :product_instance_id,
7
+ # t.string :product_instance_description
8
+ # t.integer :product_type_id
9
+ # t.string :product_type_description
10
+ # t.decimal :sold_price, :precision => 8, :scale => 2
11
+ # t.integer :sold_price_uom
12
+ # t.integer :sold_amount
13
+ # t.integer :sold_amount_uom
14
+ # t.integer :quantity
15
+ # t.integer :unit_of_measurement_id
16
+ # t.decimal :unit_price, :precision => 8, :scale => 2
17
+ # t.boolean :taxable
18
+ # t.decimal :sales_tax, :precision => 8, :scale => 2
19
+ #
20
+ # t.timestamps
21
+ # end
22
+ #
23
+ # add_index :order_line_items, :order_txn_id
24
+ # add_index :order_line_items, :order_line_item_type_id
25
+ # add_index :order_line_items, :product_instance_id
26
+ # add_index :order_line_items, :product_type_id
27
+ # add_index :order_line_items, :product_offer_id
28
+
1
29
  class OrderLineItem < ActiveRecord::Base
2
30
  attr_protected :created_at, :updated_at
3
31
 
4
- belongs_to :order_txn, :class_name => 'OrderTxn'
5
- belongs_to :order_line_item_type
6
-
7
- has_many :charge_lines, :as => :charged_item
32
+ tracks_created_by_updated_by
33
+
34
+ belongs_to :order_txn, :class_name => 'OrderTxn'
35
+ belongs_to :order_line_item_type
36
+
37
+ has_many :charge_lines, :as => :charged_item, :dependent => :destroy
8
38
 
9
39
  belongs_to :product_instance
10
40
  belongs_to :product_type
41
+ belongs_to :product_offer
11
42
 
12
43
  has_many :order_line_item_pty_roles, :dependent => :destroy
13
44
  has_many :role_types, :through => :order_line_item_pty_roles
45
+ has_many :sales_tax_lines, as: :taxed_record, dependent: :destroy
14
46
 
15
47
  ## Allow for polymorphic subtypes of this class
16
48
  belongs_to :order_line_record, :polymorphic => true
17
49
 
18
- def get_total_charges
50
+ before_destroy :destroy_order_line_item_relationships
51
+
52
+ def taxed?
53
+ line_item_record.taxable?
54
+ end
55
+
56
+ # helper method to get dba_organization related to this order_line_item
57
+ def dba_organization
58
+ order_txn.find_party_by_role('dba_org')
59
+ end
60
+
61
+ def destroy_order_line_item_relationships
62
+ OrderLineItemRelationship.where("order_line_item_id_from = ? or order_line_item_id_to = ?", self.id, self.id).destroy_all
63
+ end
64
+
65
+ # get the total charges for a order_line_item.
66
+ # The total will be returned as Money.
67
+ # There may be multiple Monies assocated with an order, such as points and
68
+ # dollars. To handle this, the method should return an array of Monies
69
+ # if a currency is passed in return the amount for only that currency
70
+ def total_amount(currency=Currency.usd)
71
+ if currency and currency.is_a?(String)
72
+ currency = Currency.send(currency)
73
+ end
74
+
75
+ charges = {}
76
+
77
+ # get sold price
78
+ # TODO currency will eventually need to be accounted for here. Solid price should probably be a money record
79
+ if self.sold_price
80
+ charges["USD"] ||= {amount: 0}
81
+ charges["USD"][:amount] += (self.sold_price * (self.quantity || 1))
82
+ end
83
+
19
84
  # get all of the charge lines associated with the order_line
20
- total_hash = Hash.new
21
85
  charge_lines.each do |charge|
22
- cur_money = charge.money
23
- cur_total = total_hash[cur_money.currency.internal_identifier]
24
- if (cur_total.nil?)
25
- cur_total = cur_money.clone
86
+ charge_money = charge.money
87
+
88
+ total_by_currency = charges[charge_money.currency.internal_identifier]
89
+ unless total_by_currency
90
+ total_by_currency = {
91
+ amount: 0
92
+ }
93
+ end
94
+
95
+ total_by_currency[:amount] += charge_money.amount unless charge_money.amount.nil?
96
+
97
+ charges[charge_money.currency.internal_identifier] = total_by_currency
98
+ end
99
+
100
+ # if currency was based only return that amount
101
+ # if there is only one currency then return that amount
102
+ # if there is more than once currency return the hash
103
+ if currency
104
+ charges[currency.internal_identifier][:amount].round(2)
105
+ elsif charges.keys.count == 1
106
+ charges
107
+ end
108
+ end
109
+
110
+ # calculates tax and save to sales_tax
111
+ def calculate_tax(ctx={})
112
+ taxation = ErpOrders::Taxation.new
113
+ tax = 0
114
+
115
+ if self.taxed?
116
+ tax = taxation.calculate_tax(self,
117
+ ctx.merge({
118
+ amount: (self.sold_price * (self.quantity || 1))
119
+ }))
120
+ end
121
+
122
+ # only get charges that are USD currency
123
+ charge_lines.joins(:money).joins(:charge_type)
124
+ .where('money.currency_id' => Currency.usd)
125
+ .where('charge_types.taxable' => true).readonly(false).each do |charge_line|
126
+ tax += charge_line.calculate_tax(ctx)
127
+ end
128
+
129
+ self.sales_tax = tax
130
+ self.save
131
+
132
+ tax
133
+ end
134
+
135
+ # Alias for to_s
136
+ def to_label
137
+ to_s
138
+ end
139
+
140
+ # description of line_item_record
141
+ def to_s
142
+ if line_item_record
143
+ line_item_record.description
144
+ else
145
+ nil
146
+ end
147
+ end
148
+
149
+ # determine the record this OrderLineItem pertains to
150
+ # can be a ProductOffer, ProductInstance or ProductType
151
+ def line_item_record
152
+ if product_offer
153
+ product_offer
154
+ else
155
+ if product_instance
156
+ product_instance
26
157
  else
27
- cur_total.amount = 0 if cur_total.amount.nil?
28
- cur_total.amount += cur_money.amount if !cur_money.amount.nil?
158
+ product_type
29
159
  end
30
- total_hash[cur_money.currency.internal_identifier] = cur_total
31
160
  end
32
- return total_hash.values
33
161
  end
162
+
163
+ def clone
164
+ order_line_item_dup = dup
165
+ order_line_item_dup.order_txn_id = nil
166
+
167
+ order_line_item_dup
168
+ end
169
+
34
170
  end
@@ -0,0 +1,6 @@
1
+ class OrderLineItemRelType < ActiveRecord::Base
2
+ attr_protected :created_at, :updated_at
3
+
4
+ acts_as_nested_set
5
+ include ErpTechSvcs::Utils::DefaultNestedSetMethods
6
+ end
@@ -0,0 +1,8 @@
1
+ class OrderLineItemRelationship < ActiveRecord::Base
2
+ attr_protected :created_at, :updated_at
3
+
4
+ belongs_to :order_line_item_from, :class_name => "OrderLineItem", :foreign_key => "order_line_item_id_from"
5
+ belongs_to :order_line_item_to, :class_name => "OrderLineItem", :foreign_key => "order_line_item_id_to"
6
+ belongs_to :order_line_item_rel_type
7
+
8
+ end
@@ -1,51 +1,163 @@
1
+ # Table Definition ##########################################
2
+ # create_table :order_txns do |t|
3
+ # t.column :description, :string
4
+ # t.column :order_txn_type_id, :integer
5
+ #
6
+ # # Multi-table inheritance info
7
+ # t.column :order_txn_record_id, :integer
8
+ # t.column :order_txn_record_type, :string
9
+ #
10
+ # # Contact Information
11
+ # t.column :email, :string
12
+ # t.column :phone_number, :string
13
+ #
14
+ # # Shipping Address
15
+ # t.column :ship_to_first_name, :string
16
+ # t.column :ship_to_last_name, :string
17
+ # t.column :ship_to_address_line_1, :string
18
+ # t.column :ship_to_address_line_2, :string
19
+ # t.column :ship_to_city, :string
20
+ # t.column :ship_to_state, :string
21
+ # t.column :ship_to_postal_code, :string
22
+ # t.column :ship_to_country, :string
23
+ #
24
+ # # Private parts
25
+ # t.column :customer_ip, :string
26
+ # t.column :order_number, :string
27
+ # t.column :error_message, :string
28
+ #
29
+ # t.timestamps
30
+ # end
31
+ #
32
+ # add_index :order_txns, :order_txn_type_id
33
+ # add_index :order_txns, [:order_txn_record_id, :order_txn_record_type], :name => 'order_txn_record_idx'
34
+ #
35
+ # add_index :order_txns, :order_txn_type_id
36
+ # add_index :order_txns, [:order_txn_record_id, :order_txn_record_type], :name => 'order_txn_record_idx'
37
+
1
38
  class OrderTxn < ActiveRecord::Base
2
39
  attr_protected :created_at, :updated_at
3
40
 
4
- # serialize custom attributes
5
- is_json :custom_fields
6
-
7
41
  acts_as_biz_txn_event
8
42
 
9
43
  belongs_to :order_txn_record, :polymorphic => true
10
- has_many :order_line_items, :dependent => :destroy
11
- has_many :charge_lines, :as => :charged_item
44
+ has_many :order_line_items, :dependent => :destroy
45
+ has_many :charge_lines, :as => :charged_item, :dependent => :destroy
12
46
 
13
47
  alias :line_items :order_line_items
14
-
48
+
15
49
  # validation
16
50
  validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :on => :update, :allow_nil => true
51
+ validates :order_number, {uniqueness: true, :allow_nil => true}
52
+
53
+ class << self
54
+ #find a order by given biz txn party role iid and party
55
+ def find_by_party_role(biz_txn_party_role_type_iid, party)
56
+ BizTxnPartyRole.where('party_id = ? and biz_txn_party_role_type_id = ?', party.id, BizTxnPartyRoleType.find_by_internal_identifier(biz_txn_party_role_type_iid).id).all.collect { |item| item.biz_txn_event.biz_txn_record }
57
+ end
58
+
59
+ def next_order_number
60
+ max_id = maximum('id')
61
+
62
+ current_order = where(OrderTxn.arel_table[:order_number].matches("%#{max_id}%")).first
17
63
 
18
- #find a order by given biz txn party role iid and party
19
- def self.find_by_party_role(biz_txn_party_role_type_iid, party)
20
- BizTxnPartyRole.where('party_id = ? and biz_txn_party_role_type_id = ?', party.id, BizTxnPartyRoleType.find_by_internal_identifier(biz_txn_party_role_type_iid).id).all.collect{|item| item.biz_txn_event.biz_txn_record}
64
+ if current_order
65
+ while current_order
66
+ max_id = max_id + 1
67
+ current_order = where(OrderTxn.arel_table[:order_number].matches("%#{max_id}%")).first
68
+ end
69
+ else
70
+ if max_id
71
+ max_id = max_id + 1
72
+ else
73
+ max_id = 1
74
+ end
75
+ end
76
+
77
+ "#{max_id}"
78
+ end
79
+ end
80
+
81
+ # helper method to get dba_organization related to this order_txn
82
+ def dba_organization
83
+ find_party_by_role('dba_org')
21
84
  end
22
85
 
23
86
  # get the total charges for an order.
24
87
  # The total will be returned as Money.
25
- # There may be multiple Monies assocated with an order, such as points and
88
+ # There may be multiple Monies associated with an order, such as points and
26
89
  # dollars. To handle this, the method should return an array of Monies
27
- #
28
- def get_total_charges
29
- # get all of the charge lines associated with the order and order_lines
30
- total_hash = Hash.new
31
- all_charges = get_all_charge_lines
32
- # loop through all of the charges and combine charges for each money type
33
- all_charges.each do |charge|
34
- cur_money = charge.money
35
- cur_total = total_hash[cur_money.currency.internal_identifier]
36
- if (cur_total.nil?)
37
- cur_total = cur_money.clone
90
+ # if a currency is passed in return the amount for only that currency
91
+ def total_amount(currency=Currency.usd)
92
+ if currency and currency.is_a?(String)
93
+ currency = Currency.send(currency)
94
+ end
95
+
96
+
97
+ charges = {"USD" => {amount: 0}}
98
+ # get any charges directly on this order_txn or on order_line_items
99
+ charge_lines.each do |charge|
100
+ charge_money = charge.money
101
+
102
+ total_by_currency = charges[charge_money.currency.internal_identifier]
103
+ unless total_by_currency
104
+ total_by_currency = {
105
+ amount: 0
106
+ }
107
+ end
108
+
109
+ total_by_currency[:amount] += charge_money.amount unless charge_money.amount.nil?
110
+
111
+ charges[charge_money.currency.internal_identifier] = total_by_currency
112
+ end
113
+
114
+ # TODO currency will eventually need to be accounted for here.
115
+ charges["USD"][:amount] += line_items.sum(&:total_amount).round(2)
116
+
117
+ # add tax
118
+ charges["USD"][:amount] += (self.sales_tax.nil? ? 0 : self.sales_tax)
119
+
120
+ if charges.empty?
121
+ 0
122
+ else
123
+ # if currency was based only return that amount
124
+ # if there is only one currency then return that amount
125
+ # if there is more than once currency return the hash
126
+ if currency
127
+ charges[currency.internal_identifier][:amount].round(2)
38
128
  else
39
- cur_total.amount = 0 if cur_total.amount.nil?
40
- cur_total.amount += cur_money.amount if !cur_money.amount.nil?
129
+ charges
41
130
  end
42
- total_hash[cur_money.currency.internal_identifier] = cur_total
43
131
  end
44
- return total_hash.values
45
132
  end
46
133
 
47
- #get all charge lines on order and order line items
48
- def get_all_charge_lines
134
+ def sub_total(currency=Currency.usd)
135
+ line_items.collect { |item| item.total_amount(currency) }.inject(:+)
136
+ end
137
+
138
+ # gets the total amount of payments made against this order via charge line payments
139
+ def total_payment_amount
140
+ amount = all_charge_lines.collect(&:total_payments).inject(:+)
141
+ if amount.nil?
142
+ 0
143
+ else
144
+ amount
145
+ end
146
+
147
+ end
148
+
149
+ # gets total amount due (total_amount - total_payments)
150
+ # only returns Currency USD
151
+ def total_amount_due
152
+ if total_amount(Currency.usd)
153
+ total_amount(Currency.usd) - total_payment_amount
154
+ else
155
+ 0
156
+ end
157
+ end
158
+
159
+ # get all charge lines on order and order line items
160
+ def all_charge_lines
49
161
  all_charges = []
50
162
  all_charges.concat(charge_lines)
51
163
  order_line_items.each do |line_item|
@@ -54,32 +166,78 @@ class OrderTxn < ActiveRecord::Base
54
166
  all_charges
55
167
  end
56
168
 
57
- def submit
58
- #Template Method
169
+ # get the total quantity of this order
170
+ def total_quantity
171
+ order_line_items.pluck(:quantity).inject(:+)
172
+ end
173
+
174
+ # calculates tax for each line item and save to sales_tax
175
+ def calculate_tax(ctx)
176
+ tax = 0
177
+ order_line_items.select { |line_item| line_item.taxed? }.each do |line_item|
178
+ tax += line_item.calculate_tax(ctx)
179
+ end
180
+
181
+ # only get charges that are USD currency
182
+ charge_lines.joins(:money)
183
+ .joins(:charge_type)
184
+ .where('money.currency_id' => Currency.usd)
185
+ .where('charge_types.taxable' => true).readonly(false).each do |charge_line|
186
+ tax += charge_line.calculate_tax(ctx)
187
+ end
188
+
189
+ self.sales_tax = tax
190
+ self.save
191
+
192
+ tax
59
193
  end
60
194
 
61
195
  #add product_type or product_instance line item
62
196
  def add_line_item(object, reln_type = nil, to_role = nil, from_role = nil)
63
- class_name = object.class.name
64
197
  if object.is_a?(Array)
65
- class_name = object.first.class.name
66
- else
67
- class_name = object.class.name
68
- end
69
-
70
- case class_name
71
- when 'ProductType'
72
- return add_product_type_line_item(object, reln_type, to_role, from_role)
73
- when 'ProductInstance'
74
- return add_product_instance_line_item(object, reln_type, to_role, from_role)
75
- end
198
+ class_name = object.first.class.name
199
+ else
200
+ class_name = object.class.name
201
+ end
202
+
203
+ case class_name
204
+ when 'ProductType'
205
+ add_product_type_line_item(object, reln_type, to_role, from_role)
206
+ when 'ProductInstance'
207
+ add_product_instance_line_item(object, reln_type, to_role, from_role)
208
+ when 'SimpleProductOffer'
209
+ add_simple_product_offer_line_item(object)
210
+ end
76
211
  end
77
212
 
78
- def add_product_type_line_item(product_type, reln_type = nil, to_role = nil, from_role = nil)
213
+ def add_simple_product_offer_line_item(simple_product_offer)
79
214
 
80
- li = OrderLineItem.new
215
+ line_item = get_line_item_for_simple_product_offer(simple_product_offer)
81
216
 
82
- if(product_type.is_a?(Array))
217
+ product_type = simple_product_offer.product_type
218
+
219
+ if line_item
220
+ ActiveRecord::Base.transaction do
221
+ line_item.quantity += 1
222
+ line_item.save
223
+ end
224
+ else
225
+ ActiveRecord::Base.transaction do
226
+ line_item = OrderLineItem.new
227
+ line_item.product_type = product_type
228
+ line_item.product_offer = simple_product_offer.product_offer
229
+ line_item.sold_price = simple_product_offer.get_current_simple_plan.money_amount
230
+ line_item.quantity = 1
231
+ line_item.save
232
+ line_items << line_item
233
+ end
234
+ end
235
+
236
+ line_item
237
+ end
238
+
239
+ def add_product_type_line_item(product_type, reln_type = nil, to_role = nil, from_role = nil)
240
+ if (product_type.is_a?(Array))
83
241
  if (product_type.size == 0)
84
242
  return
85
243
  elsif (product_type.size == 1)
@@ -107,17 +265,32 @@ class OrderTxn < ActiveRecord::Base
107
265
  product_type_for_line_item = product_type
108
266
  end
109
267
 
110
- li.product_type = product_type_for_line_item
111
- self.line_items << li
112
- li.save
113
- return li
114
- end
268
+ line_item = get_line_item_for_product_type(product_type_for_line_item)
269
+
270
+ if line_item
271
+ ActiveRecord::Base.transaction do
272
+ line_item.quantity += 1
273
+ line_item.save
274
+ end
275
+ else
276
+ ActiveRecord::Base.transaction do
277
+ line_item = OrderLineItem.new
278
+ line_item.product_type = product_type_for_line_item
279
+ line_item.sold_price = product_type_for_line_item.get_current_simple_plan.money_amount
280
+ line_item.quantity = 1
281
+ line_item.save
282
+ line_items << line_item
283
+ end
284
+ end
285
+
286
+ line_item
287
+ end
115
288
 
116
289
  def add_product_instance_line_item(product_instance, reln_type = nil, to_role = nil, from_role = nil)
117
290
 
118
291
  li = OrderLineItem.new
119
292
 
120
- if(product_instance.is_a?(Array))
293
+ if (product_instance.is_a?(Array))
121
294
  if (product_instance.size == 0)
122
295
  return
123
296
  elsif (product_instance.size == 1)
@@ -149,13 +322,24 @@ class OrderTxn < ActiveRecord::Base
149
322
  li.product_instance = product_instance_for_line_item
150
323
  self.line_items << li
151
324
  li.save
152
- return li
325
+
326
+ li
327
+ end
328
+
329
+ def get_line_item_for_product_type(product_type)
330
+ line_items.detect { |oli| oli.product_type == product_type }
331
+ end
332
+
333
+ def get_line_item_for_simple_product_offer(simple_product_offer)
334
+ line_items.detect { |oli| oli.product_offer.product_offer_record == simple_product_offer }
153
335
  end
154
336
 
155
337
  def find_party_by_role(role_type_iid)
156
338
  party = nil
157
339
 
158
- tpr = self.root_txn.biz_txn_party_roles.find(:first, :include => :biz_txn_party_role_type, :conditions => ['biz_txn_party_role_types.internal_identifier = ?',role_type_iid])
340
+ tpr = self.root_txn.biz_txn_party_roles.includes(:biz_txn_party_role_type)
341
+ .where('biz_txn_party_role_types.internal_identifier = ?', role_type_iid).first
342
+
159
343
  party = tpr.party unless tpr.nil?
160
344
 
161
345
  party
@@ -172,9 +356,23 @@ class OrderTxn < ActiveRecord::Base
172
356
  self.ship_to_city = shipping_address.city
173
357
  self.ship_to_state = shipping_address.state
174
358
  self.ship_to_postal_code = shipping_address.zip
175
- #self.ship_to_country_name = shipping_address.country_name
176
- #self.ship_to_country = shipping_address.country
359
+ # self.ship_to_country_name = shipping_address.country_name
360
+ self.ship_to_country = shipping_address.country
361
+ end
362
+ end
363
+
364
+ # Get shipping info formatted for HTML
365
+ #
366
+ def shipping_info
367
+ info = %(#{ship_to_first_name} #{ship_to_last_name}<br>#{ship_to_address_line_1})
368
+
369
+ if ship_to_address_line_2.present?
370
+ info << "<br>#{ship_to_address_line_2}"
177
371
  end
372
+
373
+ info << %(<br>#{ship_to_city} #{ship_to_state} #{ship_to_postal_code}<br>#{ship_to_country})
374
+
375
+ info
178
376
  end
179
377
 
180
378
  def set_billing_info(party)
@@ -191,11 +389,25 @@ class OrderTxn < ActiveRecord::Base
191
389
  self.bill_to_city = billing_address.city
192
390
  self.bill_to_state = billing_address.state
193
391
  self.bill_to_postal_code = billing_address.zip
194
- #self.bill_to_country_name = billing_address.country_name
195
- #self.bill_to_country = billing_address.country
392
+ # self.bill_to_country_name = billing_address.country_name
393
+ self.bill_to_country = billing_address.country
196
394
  end
197
395
  end
198
396
 
397
+ # Get billing info formatted for HTML
398
+ #
399
+ def billing_info
400
+ info = %(#{bill_to_first_name} #{bill_to_last_name}<br>#{bill_to_address_line_1}<br>)
401
+
402
+ if bill_to_address_line_2.present?
403
+ info << "<br>#{bill_to_address_line_2}"
404
+ end
405
+
406
+ info << %(<br>#{bill_to_city} #{bill_to_state} #{bill_to_postal_code}<br>#{bill_to_country})
407
+
408
+ info
409
+ end
410
+
199
411
  def determine_txn_party_roles
200
412
  #Template Method
201
413
  end
@@ -212,8 +424,8 @@ class OrderTxn < ActiveRecord::Base
212
424
  #BizTxnEvent Overrides
213
425
  ###############################################################################
214
426
  def create_dependent_txns
215
- #Template Method
216
- end
427
+ #Template Method
428
+ end
217
429
 
218
430
  ################################################################
219
431
  ################################################################
@@ -274,9 +486,9 @@ class OrderTxn < ActiveRecord::Base
274
486
  unless use_delayed_jobs
275
487
  authorized_txns.each do |financial_txn|
276
488
  result = financial_txn.capture(credit_card, gateway, gateway_options)
277
- unless(result[:success])
489
+ unless (result[:success])
278
490
  all_txns_captured = false
279
- gateway_message = result[:gateway_message]
491
+ gateway_message = result[:gateway_message]
280
492
  break
281
493
  end
282
494
  end
@@ -312,7 +524,7 @@ class OrderTxn < ActiveRecord::Base
312
524
  unless use_delayed_jobs
313
525
  authorized_txns.each do |financial_txn|
314
526
  result = financial_txn.reverse_authorization(credit_card, gateway, gateway_options)
315
- unless(result[:success])
527
+ unless (result[:success])
316
528
  all_txns_rolledback = false
317
529
  end
318
530
  end
@@ -379,4 +591,45 @@ class OrderTxn < ActiveRecord::Base
379
591
  return result, message, authorized_txns
380
592
  end
381
593
 
594
+ def clone
595
+ ActiveRecord::Base.transaction do
596
+ order_txn_dup = dup
597
+ order_txn_dup.order_txn_record_id = nil
598
+ order_txn_dup.order_txn_record_type = nil
599
+ order_txn_dup.order_number = OrderTxn.next_order_number
600
+ order_txn_dup.error_message = nil
601
+ order_txn_dup.payment_gateway_txn_id = nil
602
+ order_txn_dup.credit_card_id = nil
603
+ order_txn_dup.initialize_biz_txn_event
604
+ order_txn_dup.biz_txn_event.description = self.biz_txn_event.description
605
+
606
+ # add a relationship describing the original and the clone
607
+ biz_txn_rel_type = BizTxnRelType.find_or_create('cloned_from', 'Cloned From', nil)
608
+ BizTxnRelationship.create(txn_event_to: self.root_txn,
609
+ txn_event_from: order_txn_dup.root_txn,
610
+ biz_txn_rel_type: biz_txn_rel_type)
611
+
612
+
613
+ order_line_item_rel_type = OrderLineItemRelType.find_or_create('cloned_from', 'Cloned From', nil)
614
+
615
+ self.order_line_items.each do |order_line_item|
616
+ order_line_item_clone = order_line_item.clone
617
+ order_txn_dup.order_line_items << order_line_item_clone
618
+
619
+ OrderLineItemRelationship.create(order_line_item_from: order_line_item_clone,
620
+ order_line_item_to: order_line_item,
621
+ order_line_item_rel_type: order_line_item_rel_type)
622
+
623
+ end
624
+ order_txn_dup.save!
625
+ order_txn_dup.current_status = self.current_status
626
+
627
+ order_txn_dup
628
+ end
629
+
630
+ end
631
+
632
+ def to_label
633
+ self.order_number
634
+ end
382
635
  end