mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-02-05 22:26:07 +00:00
Merge branch 'master' into single-order-patches
This commit is contained in:
10
Gemfile.lock
10
Gemfile.lock
@@ -23,7 +23,7 @@ GIT
|
||||
|
||||
GIT
|
||||
remote: git://github.com/openfoodfoundation/spree.git
|
||||
revision: 4e0075b07acb56864aca89eee3d9670136176c23
|
||||
revision: afcc23e489eb604a3e2651598a7c8364e2acc7b3
|
||||
branch: 1-3-stable
|
||||
specs:
|
||||
spree (1.3.6.beta)
|
||||
@@ -123,7 +123,7 @@ GEM
|
||||
active_link_to (1.0.0)
|
||||
active_model_serializers (0.8.1)
|
||||
activemodel (>= 3.0)
|
||||
activemerchant (1.46.0)
|
||||
activemerchant (1.48.0)
|
||||
activesupport (>= 3.2.14, < 5.0.0)
|
||||
builder (>= 2.1.2, < 4.0.0)
|
||||
i18n (>= 0.6.9)
|
||||
@@ -181,7 +181,7 @@ GEM
|
||||
climate_control (0.0.3)
|
||||
activesupport (>= 3.0)
|
||||
cliver (0.3.2)
|
||||
cocaine (0.5.5)
|
||||
cocaine (0.5.7)
|
||||
climate_control (>= 0.0.3, < 1.0)
|
||||
coderay (1.0.9)
|
||||
coffee-rails (3.2.2)
|
||||
@@ -191,7 +191,7 @@ GEM
|
||||
coffee-script-source
|
||||
execjs
|
||||
coffee-script-source (1.3.3)
|
||||
colorize (0.7.5)
|
||||
colorize (0.7.7)
|
||||
columnize (0.3.6)
|
||||
comfortable_mexican_sofa (1.6.24)
|
||||
active_link_to (~> 1.0.0)
|
||||
@@ -496,7 +496,7 @@ GEM
|
||||
sprockets (>= 2.0.0)
|
||||
turn (0.8.3)
|
||||
ansi
|
||||
tzinfo (0.3.43)
|
||||
tzinfo (0.3.44)
|
||||
uglifier (1.2.4)
|
||||
execjs (>= 0.3.0)
|
||||
multi_json (>= 1.0.2)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
%div{ style: "display: inline-block" }
|
||||
%active-selector{ ng: { repeat: "selector in selectors()", show: "ifDefined(selector.fits, true)" } }
|
||||
%div{bindonce:true, style: "display: inline-block" }
|
||||
%active-selector{ ng: { repeat: "selector in allSelectors", show: "ifDefined(selector.fits, true)" } }
|
||||
%render-svg{path: "{{selector.object.icon}}", ng: { if: "selector.object.icon"} }
|
||||
%span {{ selector.object.name }}
|
||||
%span{"bo-text" => "selector.object.name"}
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
%div.contact-container{bindonce: true}
|
||||
%div.modal-centered{"bo-if" => "enterprise.email || enterprise.website || enterprise.phone"}
|
||||
%p.modal-header Contact
|
||||
%p{"ng-if" => "enterprise.phone"}
|
||||
{{ enterprise.phone }}
|
||||
%p{"bo-if" => "enterprise.phone", "bo-text" => "enterprise.phone"}
|
||||
|
||||
%p.word-wrap{"ng-if" => "enterprise.email"}
|
||||
%a{"ng-href" => "{{enterprise.email | stripUrl}}", target: "_blank", mailto: true}
|
||||
%span.email
|
||||
{{ enterprise.email | stripUrl }}
|
||||
%a{"bo-href" => "enterprise.email | stripUrl", target: "_blank", mailto: true}
|
||||
%span.email{"bo-bind" => "enterprise.email | stripUrl"}
|
||||
|
||||
%p.word-wrap{"ng-if" => "enterprise.website"}
|
||||
%a{"ng-href" => "http://{{enterprise.website | stripUrl}}", target: "_blank" }
|
||||
{{ enterprise.website | stripUrl }}
|
||||
%a{"bo-href-i" => "http://{{enterprise.website | stripUrl}}", target: "_blank", "bo-bind" => "enterprise.website | stripUrl"}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
.highlight{"ng-class" => "{'is_distributor' : enterprise.is_distributor}"}
|
||||
.highlight{bindonce: true, "ng-class" => "{'is_distributor' : enterprise.is_distributor}"}
|
||||
.highlight-top.row
|
||||
.small-12.medium-7.large-8.columns
|
||||
%h3{"ng-if" => "enterprise.is_distributor"}
|
||||
%a{"bo-href" => "enterprise.path", "ofn-empties-cart" => "enterprise", bindonce: true}
|
||||
%a{"bo-href" => "enterprise.path", "ofn-empties-cart" => "enterprise"}
|
||||
%i{"ng-class" => "enterprise.icon_font"}
|
||||
%span {{ enterprise.name }}
|
||||
%span{"bo-text" => "enterprise.name"}
|
||||
%h3{"ng-if" => "!enterprise.is_distributor", "ng-class" => "{'is_producer' : enterprise.is_primary_producer}"}
|
||||
%i{"ng-class" => "enterprise.icon_font"}
|
||||
%span {{ enterprise.name }}
|
||||
%span{"bo-text" => "enterprise.name"}
|
||||
.small-12.medium-5.large-4.columns.text-right.small-only-text-left
|
||||
%p {{ [enterprise.address.city, enterprise.address.state_name] | printArray}}
|
||||
%img.hero-img{"ng-src" => "{{enterprise.promo_image}}"}
|
||||
%p{"bo-bind" => "[enterprise.address.city, enterprise.address.state_name] | printArray"}
|
||||
%img.hero-img{"bo-src" => "enterprise.promo_image"}
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
%div.modal-centered{"ng-if" => "enterprise.twitter || enterprise.facebook || enterprise.linkedin || enterprise.instagram"}
|
||||
%div.modal-centered{bindonce: true, "bo-if" => "enterprise.twitter || enterprise.facebook || enterprise.linkedin || enterprise.instagram"}
|
||||
%p.modal-header Follow
|
||||
.follow-icons{bindonce: true}
|
||||
%span{"ng-if" => "enterprise.twitter"}
|
||||
%a{"ng-href" => "http://twitter.com/{{enterprise.twitter}}", target: "_blank"}
|
||||
.follow-icons
|
||||
%span{"bo-if" => "enterprise.twitter"}
|
||||
%a{"bo-href-i" => "http://twitter.com/{{enterprise.twitter}}", target: "_blank"}
|
||||
%i.ofn-i_041-twitter
|
||||
|
||||
%span{"ng-if" => "enterprise.facebook"}
|
||||
%a{"ng-href" => "http://{{enterprise.facebook | stripUrl}}", target: "_blank"}
|
||||
%span{"bo-if" => "enterprise.facebook"}
|
||||
%a{"bo-href-i" => "http://{{enterprise.facebook | stripUrl}}", target: "_blank"}
|
||||
%i.ofn-i_044-facebook
|
||||
|
||||
%span{"ng-if" => "enterprise.linkedin"}
|
||||
%a{"ng-href" => "http://{{enterprise.linkedin | stripUrl}}", target: "_blank"}
|
||||
%span{"bo-if" => "enterprise.linkedin"}
|
||||
%a{"bo-href-i" => "http://{{enterprise.linkedin | stripUrl}}", target: "_blank"}
|
||||
%i.ofn-i_042-linkedin
|
||||
|
||||
%span{"ng-if" => "enterprise.instagram"}
|
||||
%a{"ng-href" => "http://instagram.com/{{enterprise.instagram}}", target: "_blank"}
|
||||
%span{"bo-if" => "enterprise.instagram"}
|
||||
%a{"bo-href-i" => "http://instagram.com/{{enterprise.instagram}}", target: "_blank"}
|
||||
%i.ofn-i_043-instagram
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
.cta-container.small-12.columns
|
||||
%label
|
||||
Shop for
|
||||
%strong {{enterprise.name}}
|
||||
%strong{"bo-text" => "enterprise.name"}
|
||||
products at:
|
||||
%a.cta-hub{"ng-repeat" => "hub in enterprise.hubs",
|
||||
"bo-href" => "hub.path",
|
||||
@@ -10,7 +10,7 @@
|
||||
"ofn-empties-cart" => "hub"}
|
||||
%i.ofn-i_033-open-sign{"bo-if" => "hub.active"}
|
||||
%i.ofn-i_032-closed-sign{"bo-if" => "!hub.active"}
|
||||
.hub-name {{hub.name}}
|
||||
.button-address {{ hub.address.city }} , {{hub.address.state_name}}
|
||||
.hub-name{"bo-text" => "hub.name"}
|
||||
.button-address{"bo-bind" => "[hub.address.city, hub.address.state_name] | printArray"}
|
||||
/ %i.ofn-i_007-caret-right
|
||||
|
||||
|
||||
@@ -19,6 +19,6 @@
|
||||
"ofn-empties-cart" => "enterprise"}
|
||||
%i.ofn-i_033-open-sign{"bo-if" => "enterprise.active"}
|
||||
%i.ofn-i_032-closed-sign{"bo-if" => "!enterprise.active"}
|
||||
.hub-name {{enterprise.name}}
|
||||
.button-address {{ enterprise.address.city }} , {{enterprise.address.state_name}}
|
||||
.hub-name{"bo-text" => "enterprise.name"}
|
||||
.button-address{"bo-bind" => "[enterprise.address.city, enterprise.address.state_name] | printArray"}
|
||||
/ %i.ofn-i_007-caret-right
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
.row
|
||||
.row{bindonce: true}
|
||||
|
||||
.columns.small-12.large-6.product-header
|
||||
%h3 {{product.name}}
|
||||
%h3{"bo-text" => "product.name"}
|
||||
%span
|
||||
%em from
|
||||
%span.avenir {{ enterprise.name }}
|
||||
%span.avenir{"bo-text" => "enterprise.name"}
|
||||
|
||||
%br
|
||||
|
||||
@@ -18,11 +18,11 @@
|
||||
|
||||
%div{"ng-if" => "product.description"}
|
||||
%hr
|
||||
%p.text-small {{product.description}}
|
||||
%p.text-small{"bo-text" => "product.description"}
|
||||
%hr
|
||||
|
||||
.columns.small-12.large-6
|
||||
%img.product-img{"ng-src" => "{{product.largeImage}}", "ng-if" => "product.largeImage"}
|
||||
%img.product-img.placeholder{"ng-src" => "/assets/noimage/large.png", "ng-if" => "!product.largeImage"}
|
||||
%img.product-img{"bo-src" => "product.largeImage", "bo-if" => "product.largeImage"}
|
||||
%img.product-img.placeholder{"bo-src" => "'/assets/noimage/large.png'", "bo-if" => "!product.largeImage"}
|
||||
|
||||
%ng-include{src: "'partials/close.html'"}
|
||||
|
||||
3
app/assets/stylesheets/admin/icons.css.scss
Normal file
3
app/assets/stylesheets/admin/icons.css.scss
Normal file
@@ -0,0 +1,3 @@
|
||||
@import 'plugins/font-awesome';
|
||||
|
||||
.icon-refund:before { @extend .icon-ok:before }
|
||||
@@ -7,7 +7,6 @@ require 'open_food_network/customers_report'
|
||||
require 'open_food_network/users_and_enterprises_report'
|
||||
require 'open_food_network/order_cycle_management_report'
|
||||
require 'open_food_network/sales_tax_report'
|
||||
require 'open_food_network/xero_invoices_report'
|
||||
|
||||
Spree::Admin::ReportsController.class_eval do
|
||||
|
||||
@@ -15,10 +14,10 @@ Spree::Admin::ReportsController.class_eval do
|
||||
|
||||
REPORT_TYPES = {
|
||||
orders_and_fulfillment: [
|
||||
['Order Cycle Supplier Totals', :order_cycle_supplier_totals],
|
||||
['Order Cycle Supplier Totals by Distributor', :order_cycle_supplier_totals_by_distributor],
|
||||
['Order Cycle Distributor Totals by Supplier', :order_cycle_distributor_totals_by_supplier],
|
||||
['Order Cycle Customer Totals', :order_cycle_customer_totals]
|
||||
['Order Cycle Supplier Totals',:order_cycle_supplier_totals],
|
||||
['Order Cycle Supplier Totals by Distributor',:order_cycle_supplier_totals_by_distributor],
|
||||
['Order Cycle Distributor Totals by Supplier',:order_cycle_distributor_totals_by_supplier],
|
||||
['Order Cycle Customer Totals',:order_cycle_customer_totals]
|
||||
],
|
||||
products_and_inventory: [
|
||||
['All products', :all_products],
|
||||
@@ -31,16 +30,13 @@ Spree::Admin::ReportsController.class_eval do
|
||||
order_cycle_management: [
|
||||
["Payment Methods Report", :payment_methods],
|
||||
["Delivery Report", :delivery]
|
||||
],
|
||||
xero_invoices: [
|
||||
["Xero Invoices Report", :xero_invoices]
|
||||
]
|
||||
}
|
||||
|
||||
# Fetches user's distributors, suppliers and order_cycles
|
||||
before_filter :load_data, only: [:customers, :products_and_inventory, :order_cycle_management]
|
||||
|
||||
# Render a partial for various section descriptions
|
||||
# Render a partial for orders and fulfillment description
|
||||
respond_override :index => { :html => { :success => lambda {
|
||||
@reports[:orders_and_fulfillment][:description] =
|
||||
render_to_string(partial: 'orders_and_fulfillment_description', layout: false, locals: {report_types: REPORT_TYPES[:orders_and_fulfillment]}).html_safe
|
||||
@@ -327,7 +323,7 @@ Spree::Admin::ReportsController.class_eval do
|
||||
sort_by: proc { |payment_state| payment_state } },
|
||||
{ group_by: proc { |payment| payment.order.distributor },
|
||||
sort_by: proc { |distributor| distributor.name } },
|
||||
{ group_by: proc { |payment| payment.payment_method },
|
||||
{ group_by: proc { |payment| Spree::PaymentMethod.unscoped { payment.payment_method } },
|
||||
sort_by: proc { |method| method.name } } ]
|
||||
|
||||
when "itemised_payment_totals"
|
||||
@@ -676,13 +672,7 @@ Spree::Admin::ReportsController.class_eval do
|
||||
render_report(@report.header, @report.table, params[:csv], "users_and_enterprises_#{timestamp}.csv")
|
||||
end
|
||||
|
||||
def xero_invoices
|
||||
@report = OpenFoodNetwork::XeroInvoicesReport.new params
|
||||
render_report(@report.header, @report.table, params[:csv], "xero_invoices_#{timestamp}.csv")
|
||||
end
|
||||
|
||||
|
||||
def render_report(header, table, create_csv, csv_file_name)
|
||||
def render_report (header, table, create_csv, csv_file_name)
|
||||
unless create_csv
|
||||
render :html => table
|
||||
else
|
||||
@@ -719,9 +709,7 @@ Spree::Admin::ReportsController.class_eval do
|
||||
:sales_total => { :name => "Sales Total", :description => "Sales Total For All Orders" },
|
||||
:users_and_enterprises => { :name => "Users & Enterprises", :description => "Enterprise Ownership & Status" },
|
||||
:order_cycle_management => {:name => "Order Cycle Management", :description => ''},
|
||||
:sales_tax => { :name => "Sales Tax", :description => "Sales Tax For Orders" },
|
||||
:xero_invoices => { :name => "Xero invoices", :description => 'Invoices for import into Xero' }
|
||||
|
||||
:sales_tax => { :name => "Sales Tax", :description => "Sales Tax For Orders" }
|
||||
}
|
||||
# Return only reports the user is authorized to view.
|
||||
reports.select { |action| can? action, :report }
|
||||
|
||||
52
app/models/spree/payment_decorator.rb
Normal file
52
app/models/spree/payment_decorator.rb
Normal file
@@ -0,0 +1,52 @@
|
||||
module Spree
|
||||
Payment.class_eval do
|
||||
# Pin payments lacks void and credit methods, but it does have refund
|
||||
# Here we swap credit out for refund and remove void as a possible action
|
||||
def actions_with_pin_payment_adaptations
|
||||
actions = actions_without_pin_payment_adaptations
|
||||
if payment_method.is_a? Gateway::Pin
|
||||
actions << 'refund' if actions.include? 'credit'
|
||||
actions.reject! { |a| ['credit', 'void'].include? a }
|
||||
end
|
||||
actions
|
||||
end
|
||||
alias_method_chain :actions, :pin_payment_adaptations
|
||||
|
||||
|
||||
def refund!(refund_amount=nil)
|
||||
protect_from_connection_error do
|
||||
check_environment
|
||||
|
||||
refund_amount = calculate_refund_amount(refund_amount)
|
||||
|
||||
if payment_method.payment_profiles_supported?
|
||||
response = payment_method.refund((refund_amount * 100).round, source, response_code, gateway_options)
|
||||
else
|
||||
response = payment_method.refund((refund_amount * 100).round, response_code, gateway_options)
|
||||
end
|
||||
|
||||
record_response(response)
|
||||
|
||||
if response.success?
|
||||
self.class.create({ :order => order,
|
||||
:source => self,
|
||||
:payment_method => payment_method,
|
||||
:amount => refund_amount.abs * -1,
|
||||
:response_code => response.authorization,
|
||||
:state => 'completed' }, :without_protection => true)
|
||||
else
|
||||
gateway_error(response)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
def calculate_refund_amount(refund_amount=nil)
|
||||
refund_amount ||= credit_allowed >= order.outstanding_balance.abs ? order.outstanding_balance.abs : credit_allowed.abs
|
||||
refund_amount.to_f
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
@@ -20,13 +20,11 @@
|
||||
.row.pad-top{bindonce: true}
|
||||
.small-12.medium-6.columns
|
||||
.groups-header
|
||||
%a{"ng-href" => "/groups/{{group.id}}"}
|
||||
%a{"bo-href-i" => "/groups/{{group.id}}"}
|
||||
%i.ofn-i_035-groups
|
||||
%span.group-name
|
||||
{{ group.name }}
|
||||
%span.group-name{"bo-text" => "group.name"}
|
||||
.small-3.medium-2.columns
|
||||
%p
|
||||
{{ group.state }}
|
||||
%p{"bo-text" => "group.state"}
|
||||
.small-9.medium-4.columns.groups-icons
|
||||
%p
|
||||
%link-to-service.ofn-i_050-mail-circle{service: '""', ref: 'group.email.split("").reverse().join("")', mailto: true}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
.trans-sentence
|
||||
%span.fat-taxons{"ng-repeat" => "taxon in hub.taxons"}
|
||||
%render-svg{path: "{{taxon.icon}}"}
|
||||
{{taxon.name}}
|
||||
%span{"bo-text" => "taxon.name"}
|
||||
%div.show-for-medium-up{"bo-if" => "hub.taxons.length==0"}
|
||||
|
||||
.columns.small-12.medium-3.large-2.fat
|
||||
@@ -25,7 +25,6 @@
|
||||
%li{"ng-repeat" => "enterprise in hub.producers"}
|
||||
%enterprise-modal
|
||||
%i.ofn-i_036-producers
|
||||
%span
|
||||
{{ enterprise.name }}
|
||||
%span{"bo-text" => "enterprise.name"}
|
||||
%div.show-for-medium-up{"bo-if" => "hub.producers.length==0"}
|
||||
|
||||
|
||||
@@ -2,20 +2,21 @@
|
||||
|
||||
.columns.small-12.medium-6.large-5.skinny-head
|
||||
%a.hub{"bo-href" => "hub.path", "ng-class" => "{primary: hub.active, secondary: !hub.active}", "ofn-empties-cart" => "hub"}
|
||||
%i{ng: {class: "hub.icon_font"}}
|
||||
%span.margin-top.hub-name-listing {{ hub.name | truncate:40}}
|
||||
%i{bo: {class: "hub.icon_font"}}
|
||||
%span.margin-top.hub-name-listing{"bo-bind" => "hub.name | truncate:40"}
|
||||
|
||||
.columns.small-4.medium-2.large-2
|
||||
%span.margin-top {{ hub.address.city }}
|
||||
%span.margin-top{"bo-text" => "hub.address.city"}
|
||||
.columns.small-2.medium-1.large-1
|
||||
%span.margin-top {{ hub.address.state_name | uppercase }}
|
||||
%span.margin-top{"bo-bind" => "hub.address.state_name | uppercase"}
|
||||
|
||||
.columns.small-6.medium-3.large-4.text-right{"bo-if" => "hub.active"}
|
||||
%a.hub.open_closed{"bo-href" => "hub.path", "ng-class" => "{primary: hub.active, secondary: !hub.active}", "ofn-empties-cart" => "hub"}
|
||||
%i.ofn-i_033-open-sign
|
||||
%span.margin-top{ bo: { if: "current()" } }
|
||||
%em Shopping here
|
||||
%span.margin-top{ bo: { if: "!current()" } } {{ hub.orders_close_at | sensible_timeframe }}
|
||||
%span.margin-top{ bo: { if: "!current()" } }
|
||||
%span{"bo-bind" => "hub.orders_close_at | sensible_timeframe"}
|
||||
|
||||
.columns.small-6.medium-3.large-4.text-right{"bo-if" => "!hub.active"}
|
||||
%a.hub.open_closed{"bo-href" => "hub.path", "ng-class" => "{primary: hub.active, secondary: !hub.active}", "ofn-empties-cart" => "hub"}
|
||||
@@ -28,12 +29,12 @@
|
||||
.columns.small-12.medium-6.large-5.skinny-head
|
||||
%a.hub{"ng-click" => "openModal(hub)", "ng-class" => "{primary: hub.active, secondary: !hub.active}"}
|
||||
%i{ng: {class: "hub.icon_font"}}
|
||||
%span.margin-top.hub-name-listing {{ hub.name | truncate:40}}
|
||||
%span.margin-top.hub-name-listing{"bo-bind" => "hub.name | truncate:40"}
|
||||
|
||||
.columns.small-4.medium-2.large-2
|
||||
%span.margin-top {{ hub.address.city }}
|
||||
%span.margin-top{"bo-text" => "hub.address.city"}
|
||||
.columns.small-2.medium-1.large-1
|
||||
%span.margin-top {{ hub.address.state_name | uppercase }}
|
||||
%span.margin-top{"bo-bind" => "hub.address.state_name | uppercase"}
|
||||
|
||||
.columns.small-6.medium-3.large-4.text-right
|
||||
%span.margin-top{ bo: { if: "!current()" } }
|
||||
|
||||
@@ -1,68 +1,68 @@
|
||||
.row.active_table_row{"ng-show" => "open()", "ng-click" => "toggle()", "ng-class" => "{'open' : !ofn-i_032-closed-sign()}"}
|
||||
.row.active_table_row{"ng-if" => "open()", "ng-click" => "toggle()", "ng-class" => "{'open' : !ofn-i_032-closed-sign()}"}
|
||||
|
||||
.columns.small-12.medium-7.large-7.fat
|
||||
/ Will add in long description available once clean up HTML formatting producer.long_description
|
||||
%div{"bo-if" => "producer.description"}
|
||||
%label About us
|
||||
%img.right.show-for-medium-up{"ng-src" => "{{producer.logo}}" }
|
||||
%p.text-small
|
||||
{{ producer.description }}
|
||||
%img.right.show-for-medium-up{"bo-src" => "producer.logo" }
|
||||
%p.text-small{ "bo-text" => "producer.description"}
|
||||
%div.show-for-medium-up{"bo-if" => "producer.description.length==0"}
|
||||
%label
|
||||
|
||||
.columns.small-12.medium-5.large-5.fat
|
||||
|
||||
%div{"ng-if" => "producer.supplied_taxons"}
|
||||
%div{"bo-if" => "producer.supplied_taxons"}
|
||||
%label Shop for
|
||||
%p.trans-sentence
|
||||
%span.fat-taxons{"ng-repeat" => "taxon in producer.supplied_taxons"}
|
||||
%render-svg{path: "{{taxon.icon}}"}
|
||||
{{taxon.name}}
|
||||
%span{"bo-text" => "taxon.name"}
|
||||
|
||||
%div.show-for-medium-up{"ng-if" => "producer.supplied_taxons.length==0"}
|
||||
|
||||
|
||||
%div{"ng-if" => "producer.email || producer.website || producer.phone"}
|
||||
%div{"bo-if" => "producer.email || producer.website || producer.phone"}
|
||||
%label Contact
|
||||
|
||||
%p.word-wrap{"ng-if" => "producer.phone"}
|
||||
Call {{ producer.phone }}
|
||||
%p.word-wrap{"bo-if" => "producer.phone"}
|
||||
Call
|
||||
%span{"bo-text" => "producer.phone"}
|
||||
|
||||
%p.word-wrap{"ng-if" => "producer.email"}
|
||||
%a{"ng-href" => "{{producer.email | stripUrl}}", target: "_blank", mailto: true}
|
||||
%span.email {{ producer.email | stripUrl }}
|
||||
%p.word-wrap{"bo-if" => "producer.email"}
|
||||
%a{"bo-href" => "producer.email | stripUrl", target: "_blank", mailto: true}
|
||||
%span.email{"bo-bind" => "producer.email | stripUrl"}
|
||||
|
||||
%p.word-wrap{"ng-if" => "producer.website"}
|
||||
%a{"ng-href" => "http://{{producer.website | stripUrl}}", target: "_blank" }
|
||||
%span {{ producer.website | stripUrl }}
|
||||
%p.word-wrap{"bo-if" => "producer.website"}
|
||||
%a{"bo-href-i" => "http://{{producer.website | stripUrl}}", target: "_blank" }
|
||||
%span{"bo-bind" => "producer.website | stripUrl"}
|
||||
|
||||
%div{"ng-if" => "producer.twitter || producer.facebook || producer.linkedin || producer.instagram"}
|
||||
%div{"bo-if" => "producer.twitter || producer.facebook || producer.linkedin || producer.instagram"}
|
||||
%label Follow
|
||||
.follow-icons{bindonce: true}
|
||||
%span{"ng-if" => "producer.twitter"}
|
||||
%a{"ng-href" => "http://twitter.com/{{producer.twitter}}", target: "_blank"}
|
||||
%span{"bo-if" => "producer.twitter"}
|
||||
%a{"bo-href-i" => "http://twitter.com/{{producer.twitter}}", target: "_blank"}
|
||||
%i.ofn-i_041-twitter
|
||||
|
||||
%span{"ng-if" => "producer.facebook"}
|
||||
%a{"ng-href" => "http://{{producer.facebook | stripUrl}}", target: "_blank"}
|
||||
%span{"bo-if" => "producer.facebook"}
|
||||
%a{"bo-href-i" => "http://{{producer.facebook | stripUrl}}", target: "_blank"}
|
||||
%i.ofn-i_044-facebook
|
||||
|
||||
%span{"ng-if" => "producer.linkedin"}
|
||||
%a{"ng-href" => "http://{{producer.linkedin | stripUrl}}", target: "_blank"}
|
||||
%span{"bo-if" => "producer.linkedin"}
|
||||
%a{"bo-href-i" => "http://{{producer.linkedin | stripUrl}}", target: "_blank"}
|
||||
%i.ofn-i_042-linkedin
|
||||
|
||||
%span{"ng-if" => "producer.instagram"}
|
||||
%a{"ng-href" => "http://instagram.com/{{producer.instagram}}", target: "_blank"}
|
||||
%span{"bo-if" => "producer.instagram"}
|
||||
%a{"bo-href-i" => "http://instagram.com/{{producer.instagram}}", target: "_blank"}
|
||||
%i.ofn-i_043-instagram
|
||||
|
||||
.row.active_table_row.pad-top{"ng-show" => "open()", "bo-if" => "producer.hubs"}
|
||||
.row.active_table_row.pad-top{"ng-if" => "open()", "bo-if" => "producer.hubs"}
|
||||
.columns.small-12
|
||||
.row
|
||||
.columns.small-12.fat
|
||||
%div{"bo-if" => "producer.name"}
|
||||
%label
|
||||
Shop for
|
||||
%span.turquoise {{ producer.name }}
|
||||
%span.turquoise{"bo-text" => "producer.name"}
|
||||
products at:
|
||||
%div.show-for-medium-up{"bo-if" => "!producer.name"}
|
||||
|
||||
@@ -73,6 +73,6 @@
|
||||
"bo-class" => "{primary: hub.active, secondary: !hub.active}"}
|
||||
%i.ofn-i_033-open-sign{"bo-if" => "hub.active"}
|
||||
%i.ofn-i_032-closed-sign{"bo-if" => "!hub.active"}
|
||||
.hub-name {{hub.name}}
|
||||
.button-address {{ [hub.address.city, hub.address.state_name] | printArray }}
|
||||
.hub-name{"bo-text" => "hub.name"}
|
||||
.button-address{"bo-bind" => "[hub.address.city, hub.address.state_name] | printArray"}
|
||||
|
||||
|
||||
@@ -2,19 +2,19 @@
|
||||
.columns.small-12.medium-4.large-4.skinny-head
|
||||
%span{"bo-if" => "producer.is_distributor" }
|
||||
%a.is_distributor{"bo-href" => "producer.path" }
|
||||
%i{ng: {class: "producer.producer_icon_font"}}
|
||||
%i{bo: {class: "producer.producer_icon_font"}}
|
||||
%span.margin-top
|
||||
%strong {{ producer.name }}
|
||||
%strong{"bo-text" => "producer.name"}
|
||||
%span.producer-name{"bo-if" => "!producer.is_distributor" }
|
||||
%i{ng: {class: "producer.producer_icon_font"}}
|
||||
%i{bo: {class: "producer.producer_icon_font"}}
|
||||
%span.margin-top
|
||||
%strong {{ producer.name }}
|
||||
%strong{"bo-text" => "producer.name"}
|
||||
|
||||
|
||||
.columns.small-6.medium-3.large-3
|
||||
%span.margin-top {{ producer.address.city }}
|
||||
%span.margin-top{"bo-text" => "producer.address.city"}
|
||||
.columns.small-4.medium-3.large-4
|
||||
%span.margin-top {{ producer.address.state_name | uppercase }}
|
||||
%span.margin-top{"bo-bind" => "producer.address.state_name | uppercase"}
|
||||
.columns.small-2.medium-2.large-1.text-right
|
||||
%span.margin-top
|
||||
%i{"ng-class" => "{'ofn-i_005-caret-down' : !open(), 'ofn-i_006-caret-up' : open()}"}
|
||||
|
||||
@@ -7,14 +7,13 @@
|
||||
.small-10.medium-10.large-11.columns.summary-header
|
||||
%h3
|
||||
%a{"ng-click" => "triggerProductModal()"}
|
||||
{{ product.name }}
|
||||
%span{"bo-text" => "product.name"}
|
||||
%i.ofn-i_057-expand
|
||||
%small
|
||||
%em from
|
||||
%span
|
||||
%enterprise-modal
|
||||
%i.ofn-i_036-producers
|
||||
{{ enterprise.name }}
|
||||
%i.ofn-i_036-producers{"bo-text" => "enterprise.name"}
|
||||
.small-2.medium-2.large-1.columns.text-center
|
||||
.taxon-flag
|
||||
%render-svg{path: "{{product.primary_taxon.icon}}"}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
%table#listing_invoices.index
|
||||
%thead
|
||||
%tr
|
||||
- @report.header.each do |header|
|
||||
%th= header
|
||||
%tbody
|
||||
- @report.table.each do |row|
|
||||
%tr
|
||||
- row.each do |column|
|
||||
%td= column
|
||||
- if @report.table.empty?
|
||||
%tr
|
||||
%td{:colspan => "2"}= t(:none)
|
||||
@@ -134,7 +134,6 @@ Spree::Core::Engine.routes.prepend do
|
||||
match '/admin/orders/bulk_management' => 'admin/orders#bulk_management', :as => "admin_bulk_order_management"
|
||||
match '/admin/reports/products_and_inventory' => 'admin/reports#products_and_inventory', :as => "products_and_inventory_admin_reports", :via => [:get, :post]
|
||||
match '/admin/reports/customers' => 'admin/reports#customers', :as => "customers_admin_reports", :via => [:get, :post]
|
||||
match '/admin/reports/xero_invoices' => 'admin/reports#xero_invoices', :as => "xero_invoices_admin_reports", :via => [:get, :post]
|
||||
match '/admin', :to => 'admin/overview#index', :as => :admin
|
||||
match '/admin/payment_methods/show_provider_preferences' => 'admin/payment_methods#show_provider_preferences', :via => :get
|
||||
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
module OpenFoodNetwork
|
||||
class XeroInvoicesReport
|
||||
def initialize(params={})
|
||||
@params = params
|
||||
end
|
||||
|
||||
def header
|
||||
%w(*ContactName EmailAddress POAddressLine1 POAddressLine2 POAddressLine3 POAddressLine4 POCity PORegion POPostalCode POCountry *InvoiceNumber Reference *InvoiceDate *DueDate InventoryItemCode *Description *Quantity *UnitAmount Discount *AccountCode *TaxType TrackingName1 TrackingOption1 TrackingName2 TrackingOption2 Currency BrandingTheme)
|
||||
end
|
||||
|
||||
def table
|
||||
[[]]
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -297,29 +297,4 @@ feature %q{
|
||||
].sort
|
||||
end
|
||||
end
|
||||
|
||||
describe "Xero invoices report" do
|
||||
let!(:enterprise1) { create( :enterprise, owner: create_enterprise_user ) }
|
||||
let!(:enterprise2) { create( :enterprise, owner: create_enterprise_user ) }
|
||||
let!(:enterprise3) { create( :enterprise, owner: create_enterprise_user ) }
|
||||
|
||||
before do
|
||||
enterprise3.enterprise_roles.build( user: enterprise1.owner ).save
|
||||
|
||||
login_to_admin_section
|
||||
click_link 'Reports'
|
||||
|
||||
click_link 'Xero invoices'
|
||||
end
|
||||
|
||||
it "shows Xero invoices report" do
|
||||
rows = find("table#listing_invoices").all("tr")
|
||||
table = rows.map { |r| r.all("th,td").map { |c| c.text.strip } }
|
||||
|
||||
table.should == [
|
||||
%w(*ContactName EmailAddress POAddressLine1 POAddressLine2 POAddressLine3 POAddressLine4 POCity PORegion POPostalCode POCountry *InvoiceNumber Reference *InvoiceDate *DueDate InventoryItemCode *Description *Quantity *UnitAmount Discount *AccountCode *TaxType TrackingName1 TrackingOption1 TrackingName2 TrackingOption2 Currency BrandingTheme),
|
||||
[]
|
||||
]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
128
spec/models/spree/payment_spec.rb
Normal file
128
spec/models/spree/payment_spec.rb
Normal file
@@ -0,0 +1,128 @@
|
||||
require 'spec_helper'
|
||||
|
||||
module Spree
|
||||
describe Payment do
|
||||
describe "available actions" do
|
||||
context "for most gateways" do
|
||||
let(:payment) { create(:payment, source: create(:credit_card)) }
|
||||
|
||||
it "can capture and void" do
|
||||
payment.actions.sort.should == %w(capture void).sort
|
||||
end
|
||||
|
||||
describe "when a payment has been taken" do
|
||||
before do
|
||||
payment.stub(:state) { 'completed' }
|
||||
payment.stub(:order) { double(:order, payment_state: 'credit_owed') }
|
||||
end
|
||||
|
||||
it "can void and credit" do
|
||||
payment.actions.sort.should == %w(void credit).sort
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "for Pin Payments" do
|
||||
let(:d) { create(:distributor_enterprise) }
|
||||
let(:pin) { Gateway::Pin.create! name: 'pin', distributor_ids: [d.id]}
|
||||
let(:payment) { create(:payment, source: create(:credit_card), payment_method: pin) }
|
||||
|
||||
it "does not void" do
|
||||
payment.actions.should_not include 'void'
|
||||
end
|
||||
|
||||
describe "when a payment has been taken" do
|
||||
before do
|
||||
payment.stub(:state) { 'completed' }
|
||||
payment.stub(:order) { double(:order, payment_state: 'credit_owed') }
|
||||
end
|
||||
|
||||
it "can refund instead of crediting" do
|
||||
payment.actions.should_not include 'credit'
|
||||
payment.actions.should include 'refund'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "refunding" do
|
||||
let(:payment) { create(:payment) }
|
||||
let(:success) { double(:success? => true, authorization: 'abc123') }
|
||||
let(:failure) { double(:success? => false) }
|
||||
|
||||
it "always checks the environment" do
|
||||
payment.payment_method.stub(:refund) { success }
|
||||
payment.should_receive(:check_environment)
|
||||
payment.refund!
|
||||
end
|
||||
|
||||
describe "calculating refund amount" do
|
||||
it "returns the parameter amount when given" do
|
||||
payment.send(:calculate_refund_amount, 123).should === 123.0
|
||||
end
|
||||
|
||||
it "refunds up to the value of the payment when the outstanding balance is larger" do
|
||||
payment.stub(:credit_allowed) { 123 }
|
||||
payment.stub(:order) { double(:order, outstanding_balance: 1000) }
|
||||
payment.send(:calculate_refund_amount).should == 123
|
||||
end
|
||||
|
||||
it "refunds up to the outstanding balance of the order when the payment is larger" do
|
||||
payment.stub(:credit_allowed) { 1000 }
|
||||
payment.stub(:order) { double(:order, outstanding_balance: 123) }
|
||||
payment.send(:calculate_refund_amount).should == 123
|
||||
end
|
||||
end
|
||||
|
||||
describe "performing refunds" do
|
||||
before do
|
||||
payment.stub(:calculate_refund_amount) { 123 }
|
||||
payment.payment_method.should_receive(:refund).and_return(success)
|
||||
end
|
||||
|
||||
it "performs the refund without payment profiles" do
|
||||
payment.payment_method.stub(:payment_profiles_supported?) { false }
|
||||
payment.refund!
|
||||
end
|
||||
|
||||
it "performs the refund with payment profiles" do
|
||||
payment.payment_method.stub(:payment_profiles_supported?) { true }
|
||||
payment.refund!
|
||||
end
|
||||
end
|
||||
|
||||
it "records the response" do
|
||||
payment.stub(:calculate_refund_amount) { 123 }
|
||||
payment.payment_method.stub(:refund).and_return(success)
|
||||
payment.should_receive(:record_response).with(success)
|
||||
payment.refund!
|
||||
end
|
||||
|
||||
it "records a payment on success" do
|
||||
payment.stub(:calculate_refund_amount) { 123 }
|
||||
payment.payment_method.stub(:refund).and_return(success)
|
||||
payment.stub(:record_response)
|
||||
|
||||
expect do
|
||||
payment.refund!
|
||||
end.to change(Payment, :count).by(1)
|
||||
|
||||
p = Payment.last
|
||||
p.order.should == payment.order
|
||||
p.source.should == payment
|
||||
p.payment_method.should == payment.payment_method
|
||||
p.amount.should == -123
|
||||
p.response_code.should == success.authorization
|
||||
p.state.should == 'completed'
|
||||
end
|
||||
|
||||
it "logs the error on failure" do
|
||||
payment.stub(:calculate_refund_amount) { 123 }
|
||||
payment.payment_method.stub(:refund).and_return(failure)
|
||||
payment.stub(:record_response)
|
||||
payment.should_receive(:gateway_error).with(failure)
|
||||
payment.refund!
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user