erp_orders 4.0.0 → 4.2.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.
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