erp_commerce 3.0.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/GPL-3-LICENSE +674 -0
- data/README.rdoc +2 -0
- data/Rakefile +32 -0
- data/app/assets/javascripts/erp_commerce/application.js +9 -0
- data/app/assets/stylesheets/erp_commerce/application.css +7 -0
- data/app/controllers/erp_commerce/application_controller.rb +4 -0
- data/app/helpers/erp_commerce/application_helper.rb +4 -0
- data/app/models/credit_card.rb +54 -0
- data/app/models/credit_card_account.rb +4 -0
- data/app/models/credit_card_account_party_role.rb +8 -0
- data/app/models/credit_card_account_purpose.rb +6 -0
- data/app/models/credit_card_token.rb +12 -0
- data/app/models/extensions/charge_line.rb +3 -0
- data/app/models/extensions/currency.rb +3 -0
- data/app/models/extensions/financial_txn.rb +3 -0
- data/app/models/extensions/order_txn.rb +3 -0
- data/app/models/extensions/party.rb +21 -0
- data/app/models/extensions/product_instance.rb +5 -0
- data/app/models/extensions/product_type.rb +3 -0
- data/app/models/fee.rb +7 -0
- data/app/models/fee_type.rb +4 -0
- data/app/models/payment.rb +38 -0
- data/app/models/payment_gateway.rb +4 -0
- data/app/models/payment_gateway_action.rb +2 -0
- data/app/models/price.rb +25 -0
- data/app/models/price_component.rb +8 -0
- data/app/models/price_component_type.rb +3 -0
- data/app/models/pricing_plan.rb +37 -0
- data/app/models/pricing_plan_assignment.rb +6 -0
- data/app/models/pricing_plan_component.rb +36 -0
- data/app/models/valid_price_plan_component.rb +8 -0
- data/app/views/layouts/erp_commerce/application.html.erb +14 -0
- data/app/widgets/orders/base.rb +40 -0
- data/app/widgets/orders/javascript/orders.js +11 -0
- data/app/widgets/orders/views/index.html.erb +63 -0
- data/app/widgets/product_catalog/base.rb +56 -0
- data/app/widgets/product_catalog/javascript/product_catalog.js +62 -0
- data/app/widgets/product_catalog/views/add_to_cart.html.erb +10 -0
- data/app/widgets/product_catalog/views/index.html.erb +69 -0
- data/app/widgets/product_catalog/views/show.html.erb +23 -0
- data/app/widgets/shopping_cart/base.rb +178 -0
- data/app/widgets/shopping_cart/javascript/shopping_cart.js +107 -0
- data/app/widgets/shopping_cart/views/cart_items.html.erb +83 -0
- data/app/widgets/shopping_cart/views/confirmation.html.erb +10 -0
- data/app/widgets/shopping_cart/views/demographics.html.erb +142 -0
- data/app/widgets/shopping_cart/views/login.html.erb +1 -0
- data/app/widgets/shopping_cart/views/payment.html.erb +81 -0
- data/app/widgets/shopping_cart/views/price_summary.html.erb +4 -0
- data/config/routes.rb +2 -0
- data/db/data_migrations/20101011152441_payment_gateway_actions.rb +27 -0
- data/db/migrate/20100823174238_erp_commerce_base.rb +174 -0
- data/db/migrate/20100913154134_setup_payments.rb +57 -0
- data/db/migrate/20101103132342_pricing_migrations.rb +169 -0
- data/db/migrate/20110921150854_create_fees.rb +50 -0
- data/lib/erp_commerce/active_merchant_wrappers/brain_tree_gateway_wrapper.rb +66 -0
- data/lib/erp_commerce/active_merchant_wrappers/credit_card_validation.rb +34 -0
- data/lib/erp_commerce/active_merchant_wrappers.rb +2 -0
- data/lib/erp_commerce/engine.rb +15 -0
- data/lib/erp_commerce/extensions/active_record/acts_as_fee.rb +64 -0
- data/lib/erp_commerce/extensions/active_record/acts_as_priceable.rb +57 -0
- data/lib/erp_commerce/extensions.rb +2 -0
- data/lib/erp_commerce/order_helper.rb +254 -0
- data/lib/erp_commerce/version.rb +3 -0
- data/lib/erp_commerce.rb +8 -0
- data/lib/tasks/erp_commerce_tasks.rake +4 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/javascripts/application.js +9 -0
- data/spec/dummy/app/assets/stylesheets/application.css +7 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/config/application.rb +49 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +8 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/spec.rb +27 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +10 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +12 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +3 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +26 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/models/credit_card_account_party_role_spec.rb +11 -0
- data/spec/models/credit_card_account_purpose_spec.rb +11 -0
- data/spec/models/credit_card_account_spec.rb +11 -0
- data/spec/models/credit_card_spec.rb +11 -0
- data/spec/models/fee_spec.rb +11 -0
- data/spec/models/fee_type_spec.rb +11 -0
- data/spec/models/payment_gateway_action_spec.rb +11 -0
- data/spec/models/payment_gateway_spec.rb +11 -0
- data/spec/models/payment_spec.rb +11 -0
- data/spec/models/price_component_spec.rb +11 -0
- data/spec/models/price_component_type_spec.rb +11 -0
- data/spec/models/price_spec.rb +11 -0
- data/spec/models/pricing_plan_assignment_spec.rb +11 -0
- data/spec/models/pricing_plan_component_spec.rb +11 -0
- data/spec/models/pricing_plan_spec.rb +11 -0
- data/spec/models/valid_price_plan_component_spec.rb +11 -0
- data/spec/spec_helper.rb +60 -0
- metadata +285 -0
data/Rakefile
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/env rake
|
|
2
|
+
begin
|
|
3
|
+
require 'bundler/setup'
|
|
4
|
+
rescue LoadError
|
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
|
6
|
+
end
|
|
7
|
+
begin
|
|
8
|
+
require 'rdoc/task'
|
|
9
|
+
rescue LoadError
|
|
10
|
+
require 'rdoc/rdoc'
|
|
11
|
+
require 'rake/rdoctask'
|
|
12
|
+
RDoc::Task = Rake::RDocTask
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
|
17
|
+
rdoc.title = 'ErpCommerce'
|
|
18
|
+
rdoc.options << '--line-numbers'
|
|
19
|
+
rdoc.rdoc_files.include('README.rdoc')
|
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
|
|
24
|
+
load 'rails/tasks/engine.rake'
|
|
25
|
+
|
|
26
|
+
Bundler::GemHelper.install_tasks
|
|
27
|
+
|
|
28
|
+
require "rspec/core/rake_task"
|
|
29
|
+
RSpec::Core::RakeTask.new(:spec)
|
|
30
|
+
task :default => :spec
|
|
31
|
+
|
|
32
|
+
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// This is a manifest file that'll be compiled into including all the files listed below.
|
|
2
|
+
// Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
|
|
3
|
+
// be included in the compiled file accessible from http://example.com/assets/application.js
|
|
4
|
+
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
|
5
|
+
// the compiled file.
|
|
6
|
+
//
|
|
7
|
+
//= require jquery
|
|
8
|
+
//= require jquery_ujs
|
|
9
|
+
//= require_tree .
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This is a manifest file that'll automatically include all the stylesheets available in this directory
|
|
3
|
+
* and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
|
|
4
|
+
* the top of the compiled file, but it's generally better to create a new file per style scope.
|
|
5
|
+
*= require_self
|
|
6
|
+
*= require_tree .
|
|
7
|
+
*/
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
class CreditCard < ActiveRecord::Base
|
|
2
|
+
|
|
3
|
+
require 'attr_encrypted'
|
|
4
|
+
|
|
5
|
+
belongs_to :postal_address
|
|
6
|
+
has_many :payments
|
|
7
|
+
belongs_to :credit_card_account_party_role
|
|
8
|
+
|
|
9
|
+
#the function EncryptionKey.get_key is meant to be overridden to provide a means for implementations to specify their
|
|
10
|
+
#own encryption schemes and locations. It will default to a simple string for development and testing
|
|
11
|
+
attr_encrypted :private_card_number, :key => EncryptionKey.get_key, :marshall => true, :attribute => :crypted_private_card_number
|
|
12
|
+
|
|
13
|
+
# These methods are exposed for the purposes of displaying a version of the card number
|
|
14
|
+
# string containing the last four digits of the card number. The idea is to make it
|
|
15
|
+
# painfully obvious when any coder is using the private_card_number, which should
|
|
16
|
+
# be used only in limited circumstances.
|
|
17
|
+
|
|
18
|
+
def card_number
|
|
19
|
+
if self.private_card_number
|
|
20
|
+
n = self.private_card_number
|
|
21
|
+
'xxxx-xxxx-xxxx-' + n[n.length-4..n.length]
|
|
22
|
+
else
|
|
23
|
+
''
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Note that the setter method allows the same variable to be set, and delegates through
|
|
28
|
+
# the encryption process
|
|
29
|
+
|
|
30
|
+
def card_number=(num)
|
|
31
|
+
self.private_card_number=num
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def to_label
|
|
35
|
+
"#{card_type}: #{card_number}"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def to_s
|
|
39
|
+
"#{card_type}: #{card_number}"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def cardholder
|
|
43
|
+
return self.credit_card_account_party_role.party
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def before_create
|
|
47
|
+
token = CreditCardToken.new
|
|
48
|
+
self.credit_card_token = token.cc_token.strip
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
Party.class_eval do
|
|
2
|
+
|
|
3
|
+
#credit cards
|
|
4
|
+
has_many :credit_card_account_party_roles
|
|
5
|
+
|
|
6
|
+
# return primary credit card
|
|
7
|
+
def primary_credit_card
|
|
8
|
+
return get_credit_card('primary')
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# return credit card by credit card account purpose using internal identifier
|
|
12
|
+
def get_credit_card(internal_identifier)
|
|
13
|
+
self.credit_card_account_party_roles.each do |ccapr|
|
|
14
|
+
if ccapr.credit_card_account.credit_card_account_purpose.internal_identifier.eql?(internal_identifier)
|
|
15
|
+
return ccapr.credit_card
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
return nil
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
data/app/models/fee.rb
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
class Payment < ActiveRecord::Base
|
|
2
|
+
include AASM
|
|
3
|
+
|
|
4
|
+
belongs_to :financial_txn
|
|
5
|
+
has_many :payment_gateways
|
|
6
|
+
|
|
7
|
+
aasm_column :current_state
|
|
8
|
+
|
|
9
|
+
aasm_initial_state :pending
|
|
10
|
+
|
|
11
|
+
aasm_state :pending
|
|
12
|
+
aasm_state :declined
|
|
13
|
+
aasm_state :authorized
|
|
14
|
+
aasm_state :captured
|
|
15
|
+
aasm_state :authorization_reversed
|
|
16
|
+
|
|
17
|
+
aasm_event :authorize do
|
|
18
|
+
transitions :to => :authorized, :from => [:pending]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
aasm_event :purchase do
|
|
22
|
+
transitions :to => :captured, :from => [:authorized, :pending]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
aasm_event :decline do
|
|
26
|
+
transitions :to => :declined, :from => [:pending]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
aasm_event :capture do
|
|
30
|
+
transitions :to => :captured, :from => [:authorized]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
aasm_event :reverse_authorization do
|
|
34
|
+
transitions :to => :authorization_reversed, :from => [:authorized]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
end
|
data/app/models/price.rb
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
class Price < ActiveRecord::Base
|
|
2
|
+
|
|
3
|
+
belongs_to :pricing_plan
|
|
4
|
+
belongs_to :priced_item, :polymorphic => true
|
|
5
|
+
has_many :price_components, :dependent => :destroy
|
|
6
|
+
belongs_to :money
|
|
7
|
+
|
|
8
|
+
alias :components :price_components
|
|
9
|
+
|
|
10
|
+
def get_price_components_by_type(type_iid)
|
|
11
|
+
self.price_components.select{|pc| pc.pricing_plan_component.price_component_type.internal_identifier == type_iid}
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def get_total_by_type(type_iid)
|
|
15
|
+
total = 0
|
|
16
|
+
|
|
17
|
+
components = self.price_components.select{|pc| pc.pricing_plan_component.price_component_type.internal_identifier == type_iid}
|
|
18
|
+
components.each do |component|
|
|
19
|
+
total = total + component.money.amount
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
total
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
class PricingPlan < ActiveRecord::Base
|
|
2
|
+
|
|
3
|
+
has_many :valid_price_plan_components
|
|
4
|
+
has_many :pricing_plan_components, :through => :valid_price_plan_components
|
|
5
|
+
belongs_to :currency
|
|
6
|
+
|
|
7
|
+
alias :components :pricing_plan_components
|
|
8
|
+
|
|
9
|
+
def get_price( rule_ctx = nil )
|
|
10
|
+
|
|
11
|
+
price = Price.new
|
|
12
|
+
price.pricing_plan = self
|
|
13
|
+
|
|
14
|
+
#first check if this is a simple amount if so get the amount.
|
|
15
|
+
if self.is_simple_amount
|
|
16
|
+
price.money = Money.new(:amount => self.money_amount, :currency => self.currency)
|
|
17
|
+
|
|
18
|
+
#second check if a pricing calculation exists if so use it.
|
|
19
|
+
elsif !self.pricing_calculation.nil?
|
|
20
|
+
rule_ctx[:pricing_plan] = self
|
|
21
|
+
rule_ctx[:price] = price
|
|
22
|
+
eval(self.pricing_calculation)
|
|
23
|
+
|
|
24
|
+
#finanlly if this is not a simple amount and has no pricing calcuation use the price components associated to this plan
|
|
25
|
+
else
|
|
26
|
+
self.pricing_plan_components.each do |pricing_plan_component|
|
|
27
|
+
price_component = pricing_plan_component.get_price_component(rule_ctx)
|
|
28
|
+
price.components << price_component
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
price.description = self.description
|
|
33
|
+
|
|
34
|
+
price
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
class PricingPlanComponent < ActiveRecord::Base
|
|
2
|
+
|
|
3
|
+
#these relationships essentially mean that pricing plan components can
|
|
4
|
+
#be shared across pricing plan. This is accomplished by using a cross-reference
|
|
5
|
+
#table called 'valid_price_plan_components'
|
|
6
|
+
has_many :valid_price_plan_components
|
|
7
|
+
has_many :pricing_plans, :through => :valid_price_plan_components
|
|
8
|
+
belongs_to :price_component_type
|
|
9
|
+
belongs_to :currency
|
|
10
|
+
|
|
11
|
+
def get_price_component( rule_ctx = nil )
|
|
12
|
+
|
|
13
|
+
#this will be relaced by an execution of the stored 'matching_rule' and 'pricing_calculation'
|
|
14
|
+
#although it might make sense to have an 'is_simple' flag and corresponding value so the price
|
|
15
|
+
#component can simply create one price component with one float value without invoking a rules
|
|
16
|
+
#engine or the interpreter
|
|
17
|
+
|
|
18
|
+
if self.is_simple_amount
|
|
19
|
+
component_amount = self.money_amount
|
|
20
|
+
else
|
|
21
|
+
component_amount = eval(self.pricing_calculation)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
money = Money.new(:description => self.description, :amount => component_amount, :currency => self.currency)
|
|
25
|
+
|
|
26
|
+
price_component = PriceComponent.new(
|
|
27
|
+
:money => money,
|
|
28
|
+
:pricing_plan_component => self,
|
|
29
|
+
:description => self.description
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
price_component
|
|
33
|
+
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>ErpCommerce</title>
|
|
5
|
+
<%= stylesheet_link_tag "erp_commerce/application" %>
|
|
6
|
+
<%= javascript_include_tag "erp_commerce/application" %>
|
|
7
|
+
<%= csrf_meta_tags %>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
|
|
11
|
+
<%= yield %>
|
|
12
|
+
|
|
13
|
+
</body>
|
|
14
|
+
</html>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module Widgets
|
|
2
|
+
module Orders
|
|
3
|
+
class Base < ErpApp::Widgets::Base
|
|
4
|
+
def index
|
|
5
|
+
@orders = OrderTxn.find_by_party_role('buyer', current_user.party)
|
|
6
|
+
@orders = @orders.select{|order| order.status != "Initialized"}
|
|
7
|
+
render
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
#should not be modified
|
|
11
|
+
#modify at your own risk
|
|
12
|
+
def locate
|
|
13
|
+
File.dirname(__FILE__)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
class << self
|
|
17
|
+
def title
|
|
18
|
+
"Orders"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def views_location
|
|
22
|
+
File.join(File.dirname(__FILE__),"/views")
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def widget_name
|
|
26
|
+
File.basename(File.dirname(__FILE__))
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def base_layout
|
|
30
|
+
begin
|
|
31
|
+
file = File.join(File.dirname(__FILE__),"/views/layouts/base.html.erb")
|
|
32
|
+
IO.read(file)
|
|
33
|
+
rescue
|
|
34
|
+
return nil
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end#Base
|
|
39
|
+
end#Orders
|
|
40
|
+
end#Widgets
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Compass.ErpApp.Widgets.Orders = {
|
|
2
|
+
add:function(){
|
|
3
|
+
Ext.getCmp('knitkitCenterRegion').addContentToActiveCodeMirror("<%= render_widget :orders %>");
|
|
4
|
+
}
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
Compass.ErpApp.Widgets.AvailableWidgets.push({
|
|
8
|
+
name:'Orders',
|
|
9
|
+
iconUrl:'/images/icons/package/package_48x48.png',
|
|
10
|
+
onClick:Compass.ErpApp.Widgets.Orders.add
|
|
11
|
+
});
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
<style type="text/css">
|
|
2
|
+
#products-view {
|
|
3
|
+
font-family:'Lucida Grande','Lucida Sans Unicode',sans-serif;
|
|
4
|
+
text-align:center;
|
|
5
|
+
font-size:14px;
|
|
6
|
+
width:100%;
|
|
7
|
+
border-collapse: collapse;
|
|
8
|
+
border: 2px solid #CCCCCC;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
#products-view a {
|
|
12
|
+
text-decoration:none;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
#products-view img {
|
|
16
|
+
height:60px;
|
|
17
|
+
width:65px;
|
|
18
|
+
padding-right:15px;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
#products-view div
|
|
22
|
+
{
|
|
23
|
+
float:left;
|
|
24
|
+
text-align:left;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
#products-view th {
|
|
28
|
+
padding: 0 0.5em;
|
|
29
|
+
height:30px;
|
|
30
|
+
text-align:center;
|
|
31
|
+
background:url("/images/knitkit/footer.png") repeat-x scroll 0 0 #29425E;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.highlight:hover
|
|
35
|
+
{
|
|
36
|
+
background-color:#FFFFEE;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
#products-view td+td {
|
|
40
|
+
border-left: 1px solid #CCC;
|
|
41
|
+
text-align: center;
|
|
42
|
+
}
|
|
43
|
+
</style>
|
|
44
|
+
<table id="products-view">
|
|
45
|
+
<thead>
|
|
46
|
+
<tr>
|
|
47
|
+
<th>Order Number</th>
|
|
48
|
+
<th>Order At</th>
|
|
49
|
+
<th>Status</th>
|
|
50
|
+
<th>Amount</th>
|
|
51
|
+
</tr>
|
|
52
|
+
</thead>
|
|
53
|
+
<tbody>
|
|
54
|
+
<% @orders.each do |order| %>
|
|
55
|
+
<tr>
|
|
56
|
+
<td><%=order.order_number%></td>
|
|
57
|
+
<td><%=order.created_at.to_time.strftime("%m/%d/%Y %I:%M%p")%></td>
|
|
58
|
+
<td><%=order.status%></td>
|
|
59
|
+
<td><%=number_to_currency(order.get_total_charges.sum{|money| money.amount})%></td>
|
|
60
|
+
</tr>
|
|
61
|
+
<% end %>
|
|
62
|
+
</tbody>
|
|
63
|
+
</table>
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
module Widgets
|
|
2
|
+
module ProductCatalog
|
|
3
|
+
class Base < ErpApp::Widgets::Base
|
|
4
|
+
def index
|
|
5
|
+
render
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def back_to_catalog
|
|
9
|
+
render :update => {:id => "#{@uuid}_result", :view => 'index'}
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def show
|
|
13
|
+
@product_type = ProductType.find(params[:id])
|
|
14
|
+
render :update => {:id => "#{@uuid}_result", :view => 'show'}
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def add_to_cart
|
|
18
|
+
@product_type = ProductType.find(params[:id])
|
|
19
|
+
@cart_items_url = params[:cart_items_url]
|
|
20
|
+
ErpCommerce::OrderHelper.new(self).add_to_cart(@product_type)
|
|
21
|
+
|
|
22
|
+
render :update => {:id => "#{@uuid}_result", :view => 'add_to_cart'}
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
#should not be modified
|
|
26
|
+
#modify at your own risk
|
|
27
|
+
def locate
|
|
28
|
+
File.dirname(__FILE__)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
class << self
|
|
32
|
+
def title
|
|
33
|
+
"Product Catalog"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def views_location
|
|
37
|
+
File.join(File.dirname(__FILE__),"/views")
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def widget_name
|
|
41
|
+
File.basename(File.dirname(__FILE__))
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def base_layout
|
|
45
|
+
begin
|
|
46
|
+
file = File.join(File.dirname(__FILE__),"/views/layouts/base.html.erb")
|
|
47
|
+
IO.read(file)
|
|
48
|
+
rescue
|
|
49
|
+
return nil
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end#Base
|
|
54
|
+
end#ProductCatalog
|
|
55
|
+
end#Widgets
|
|
56
|
+
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
Compass.ErpApp.Widgets.ProductCatalog = {
|
|
2
|
+
add:function(){
|
|
3
|
+
var addProductCatalogWidgetWindow = Ext.create("Ext.window.Window",{
|
|
4
|
+
layout:'fit',
|
|
5
|
+
width:300,
|
|
6
|
+
title:'Add Product Catalog Widget',
|
|
7
|
+
height:100,
|
|
8
|
+
buttonAlign:'center',
|
|
9
|
+
items: Ext.create("Ext.form.Panel",{
|
|
10
|
+
labelWidth: 100,
|
|
11
|
+
frame:false,
|
|
12
|
+
bodyStyle:'padding:5px 5px 0',
|
|
13
|
+
defaults: {
|
|
14
|
+
width: 225
|
|
15
|
+
},
|
|
16
|
+
items: [
|
|
17
|
+
{
|
|
18
|
+
xtype:'textfield',
|
|
19
|
+
fieldLabel:'Cart Items Url',
|
|
20
|
+
name:'cartItemsUrl',
|
|
21
|
+
hidden:false,
|
|
22
|
+
value:'/cart-items'
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}),
|
|
26
|
+
buttons: [{
|
|
27
|
+
text:'Submit',
|
|
28
|
+
handler:function(button){
|
|
29
|
+
var window = button.findParentByType('window');
|
|
30
|
+
var formPanel = window.query('form')[0];
|
|
31
|
+
var basicForm = formPanel.getForm();
|
|
32
|
+
var cartItemsUrl = basicForm.findField('cartItemsUrl').getValue();
|
|
33
|
+
var data = {
|
|
34
|
+
cartItemsUrl:cartItemsUrl
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
var tpl = new Ext.XTemplate("<%= render_widget :product_catalog,\n",
|
|
38
|
+
" :action => :index,\n",
|
|
39
|
+
" :params => {:cart_items_url => '{cartItemsUrl}'} %>");
|
|
40
|
+
|
|
41
|
+
//add rendered template to center region editor
|
|
42
|
+
Ext.getCmp('knitkitCenterRegion').addContentToActiveCodeMirror(tpl.apply(data));
|
|
43
|
+
addProductCatalogWidgetWindow.close();
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
text: 'Close',
|
|
48
|
+
handler: function(){
|
|
49
|
+
addProductCatalogWidgetWindow.close();
|
|
50
|
+
}
|
|
51
|
+
}]
|
|
52
|
+
|
|
53
|
+
});
|
|
54
|
+
addProductCatalogWidgetWindow.show();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
Compass.ErpApp.Widgets.AvailableWidgets.push({
|
|
59
|
+
name:'Product Catalog',
|
|
60
|
+
iconUrl:'/images/icons/product/product_48x48.png',
|
|
61
|
+
onClick:Compass.ErpApp.Widgets.ProductCatalog.add
|
|
62
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<%= @product_type.description %>
|
|
2
|
+
<br/>
|
|
3
|
+
<p><%= raw @product_type.find_description_by_iid('long_description').description %></p>
|
|
4
|
+
<br/>
|
|
5
|
+
Added to cart
|
|
6
|
+
<br/>
|
|
7
|
+
<%=link_to_remote 'Continue Shopping', build_widget_url(:index)%> | <a href="<%=@cart_items_url%>">Go to Cart</a>
|
|
8
|
+
<script type="text/javascript">
|
|
9
|
+
Compass.ErpApp.Widgets.refreshWidget('shopping_cart', 'price_summary');
|
|
10
|
+
</script>
|