mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-24 20:36:49 +00:00
Merge pull request #6643 from coopdevs/customer-balance-frontoffice
Customer balance frontoffice
This commit is contained in:
@@ -12,9 +12,13 @@ module Spree
|
||||
before_action :set_locale
|
||||
before_action :enable_embedded_shopfront
|
||||
|
||||
# Ignores invoice orders, only order where state: 'complete'
|
||||
def show
|
||||
@orders = @user.orders.where(state: 'complete').order('completed_at desc')
|
||||
@orders = orders_collection
|
||||
|
||||
customers = spree_current_user.customers
|
||||
@shops = Enterprise
|
||||
.where(id: @orders.pluck(:distributor_id).uniq | customers.pluck(:enterprise_id))
|
||||
|
||||
@unconfirmed_email = spree_current_user.unconfirmed_email
|
||||
end
|
||||
|
||||
@@ -54,6 +58,14 @@ module Spree
|
||||
|
||||
private
|
||||
|
||||
def orders_collection
|
||||
if OpenFoodNetwork::FeatureToggle.enabled?(:customer_balance, spree_current_user)
|
||||
CompleteOrdersWithBalance.new(@user).query
|
||||
else
|
||||
@user.orders.where(state: 'complete').order('completed_at desc')
|
||||
end
|
||||
end
|
||||
|
||||
def load_object
|
||||
@user ||= spree_current_user
|
||||
if @user
|
||||
|
||||
@@ -130,6 +130,11 @@ module Spree
|
||||
where("state != ?", state)
|
||||
}
|
||||
|
||||
# All the states an order can be in after completing the checkout
|
||||
FINALIZED_STATES = %w(complete canceled resumed awaiting_return returned).freeze
|
||||
|
||||
scope :finalized, -> { where(state: FINALIZED_STATES) }
|
||||
|
||||
def self.by_number(number)
|
||||
where(number: number)
|
||||
end
|
||||
|
||||
21
app/queries/complete_orders_with_balance.rb
Normal file
21
app/queries/complete_orders_with_balance.rb
Normal file
@@ -0,0 +1,21 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Fetches complete orders of the specified user including their balance as a computed column
|
||||
class CompleteOrdersWithBalance
|
||||
def initialize(user)
|
||||
@user = user
|
||||
end
|
||||
|
||||
def query
|
||||
OutstandingBalance.new(sorted_finalized_orders).query
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def sorted_finalized_orders
|
||||
@user.orders
|
||||
.finalized
|
||||
.select('spree_orders.*')
|
||||
.order(completed_at: :desc)
|
||||
end
|
||||
end
|
||||
39
app/queries/customers_with_balance.rb
Normal file
39
app/queries/customers_with_balance.rb
Normal file
@@ -0,0 +1,39 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Fetches the customers of the specified enterprise including the aggregated balance across the
|
||||
# customer's orders. That is, we get the total balance for each customer with this enterprise.
|
||||
class CustomersWithBalance
|
||||
def initialize(enterprise)
|
||||
@enterprise = enterprise
|
||||
end
|
||||
|
||||
def query
|
||||
Customer.of(enterprise).
|
||||
joins(left_join_complete_orders).
|
||||
group("customers.id").
|
||||
select("customers.*").
|
||||
select(outstanding_balance_sum)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :enterprise
|
||||
|
||||
def outstanding_balance_sum
|
||||
"SUM(#{OutstandingBalance.new.statement}) AS balance_value"
|
||||
end
|
||||
|
||||
# The resulting orders are in states that belong after the checkout. Only these can be considered
|
||||
# for a customer's balance.
|
||||
def left_join_complete_orders
|
||||
<<-SQL.strip_heredoc
|
||||
LEFT JOIN spree_orders ON spree_orders.customer_id = customers.id
|
||||
AND #{finalized_states.to_sql}
|
||||
SQL
|
||||
end
|
||||
|
||||
def finalized_states
|
||||
states = Spree::Order::FINALIZED_STATES.map { |state| Arel::Nodes.build_quoted(state) }
|
||||
Arel::Nodes::In.new(Spree::Order.arel_table[:state], states)
|
||||
end
|
||||
end
|
||||
44
app/queries/outstanding_balance.rb
Normal file
44
app/queries/outstanding_balance.rb
Normal file
@@ -0,0 +1,44 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Encapsulates the SQL statement that computes the balance of an order as a new column in the result
|
||||
# set. This can then be reused chaining it with the ActiveRecord::Relation objects you pass in the
|
||||
# constructor.
|
||||
#
|
||||
# Alternatively, you can get the SQL by calling #statement, which is suitable for more complex
|
||||
# cases.
|
||||
#
|
||||
# See CompleteOrdersWithBalance or CustomersWithBalance as examples.
|
||||
class OutstandingBalance
|
||||
# All the states of a finished order but that shouldn't count towards the balance (the customer
|
||||
# didn't get the order for whatever reason). Note it does not include complete
|
||||
FINALIZED_NON_SUCCESSFUL_STATES = %w(canceled returned).freeze
|
||||
|
||||
# The relation must be an ActiveRecord::Relation object with `spree_orders` in the SQL statement
|
||||
# FROM for #statement to work.
|
||||
def initialize(relation = nil)
|
||||
@relation = relation
|
||||
end
|
||||
|
||||
def query
|
||||
relation.select("#{statement} AS balance_value")
|
||||
end
|
||||
|
||||
# Arel doesn't support CASE statements until v7.1.0 so we'll have to wait with SQL literals
|
||||
# a little longer. See https://github.com/rails/arel/pull/400 for details.
|
||||
def statement
|
||||
<<-SQL.strip_heredoc
|
||||
CASE WHEN state IN #{non_fulfilled_states_group.to_sql} THEN payment_total
|
||||
WHEN state IS NOT NULL THEN payment_total - total
|
||||
ELSE 0 END
|
||||
SQL
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :relation
|
||||
|
||||
def non_fulfilled_states_group
|
||||
states = FINALIZED_NON_SUCCESSFUL_STATES.map { |state| Arel::Nodes.build_quoted(state) }
|
||||
Arel::Nodes::Grouping.new(states)
|
||||
end
|
||||
end
|
||||
@@ -7,6 +7,14 @@ module Api
|
||||
|
||||
has_many :payments, serializer: Api::PaymentSerializer
|
||||
|
||||
def outstanding_balance
|
||||
if OpenFoodNetwork::FeatureToggle.enabled?(:customer_balance, object.user)
|
||||
-object.balance_value
|
||||
else
|
||||
object.outstanding_balance
|
||||
end
|
||||
end
|
||||
|
||||
def payments
|
||||
object.payments.joins(:payment_method).completed
|
||||
end
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class CustomersWithBalance
|
||||
def initialize(enterprise)
|
||||
@enterprise = enterprise
|
||||
end
|
||||
|
||||
def query
|
||||
Customer.of(enterprise).
|
||||
joins(left_join_complete_orders).
|
||||
group("customers.id").
|
||||
select("customers.*").
|
||||
select(outstanding_balance)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :enterprise
|
||||
|
||||
# Arel doesn't support CASE statements until v7.1.0 so we'll have to wait with SQL literals
|
||||
# a little longer. See https://github.com/rails/arel/pull/400 for details.
|
||||
def outstanding_balance
|
||||
<<-SQL.strip_heredoc
|
||||
SUM(
|
||||
CASE WHEN state IN #{non_fulfilled_states_group.to_sql} THEN payment_total
|
||||
WHEN state IS NOT NULL THEN payment_total - total
|
||||
ELSE 0 END
|
||||
) AS balance_value
|
||||
SQL
|
||||
end
|
||||
|
||||
# The resulting orders are in states that belong after the checkout. Only these can be considered
|
||||
# for a customer's balance.
|
||||
def left_join_complete_orders
|
||||
<<-SQL.strip_heredoc
|
||||
LEFT JOIN spree_orders ON spree_orders.customer_id = customers.id
|
||||
AND #{complete_orders.to_sql}
|
||||
SQL
|
||||
end
|
||||
|
||||
def complete_orders
|
||||
states_group = prior_to_completion_states.map { |state| Arel::Nodes.build_quoted(state) }
|
||||
Arel::Nodes::NotIn.new(Spree::Order.arel_table[:state], states_group)
|
||||
end
|
||||
|
||||
def non_fulfilled_states_group
|
||||
states_group = non_fulfilled_states.map { |state| Arel::Nodes.build_quoted(state) }
|
||||
Arel::Nodes::Grouping.new(states_group)
|
||||
end
|
||||
|
||||
# All the states an order can be in before completing the checkout
|
||||
def prior_to_completion_states
|
||||
%w(cart address delivery payment)
|
||||
end
|
||||
|
||||
# All the states of a complete order but that shouldn't count towards the balance. Those that the
|
||||
# customer won't enjoy.
|
||||
def non_fulfilled_states
|
||||
%w(canceled returned)
|
||||
end
|
||||
end
|
||||
@@ -1,7 +1,8 @@
|
||||
- content_for :injection_data do
|
||||
= inject_orders
|
||||
= inject_shops
|
||||
= inject_json_array("orders", @orders.all, Api::OrderSerializer)
|
||||
= inject_json_array("shops", @shops.all, Api::ShopForOrdersSerializer)
|
||||
= inject_saved_credit_cards
|
||||
|
||||
- if Stripe.publishable_key
|
||||
:javascript
|
||||
angular.module('Darkswarm').value("stripeObject", Stripe("#{Stripe.publishable_key}"))
|
||||
|
||||
@@ -40,6 +40,22 @@ describe Spree::UsersController, type: :controller do
|
||||
# Doesn't return uncompleted orders" do
|
||||
expect(orders).not_to include d1o3
|
||||
end
|
||||
|
||||
context 'when the customer_balance feature is enabled' do
|
||||
let(:outstanding_balance) { double(:outstanding_balance) }
|
||||
|
||||
before do
|
||||
allow(OpenFoodNetwork::FeatureToggle)
|
||||
.to receive(:enabled?).with(:customer_balance, controller.spree_current_user) { true }
|
||||
end
|
||||
|
||||
it 'calls OutstandingBalance' do
|
||||
allow(OutstandingBalance).to receive(:new).and_return(outstanding_balance)
|
||||
expect(outstanding_balance).to receive(:query) { Spree::Order.none }
|
||||
|
||||
spree_get :show
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "registered_email" do
|
||||
|
||||
61
spec/queries/complete_orders_with_balance_spec.rb
Normal file
61
spec/queries/complete_orders_with_balance_spec.rb
Normal file
@@ -0,0 +1,61 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe CompleteOrdersWithBalance do
|
||||
let(:complete_orders_with_balance) { described_class.new(user) }
|
||||
|
||||
describe '#query' do
|
||||
let(:user) { order.user }
|
||||
let(:outstanding_balance) { instance_double(OutstandingBalance) }
|
||||
|
||||
context 'when the user has complete orders' do
|
||||
let(:order) do
|
||||
create(:order, state: 'complete', total: 2.0, payment_total: 1.0, completed_at: 2.day.ago)
|
||||
end
|
||||
let!(:other_order) do
|
||||
create(
|
||||
:order,
|
||||
user: user,
|
||||
state: 'complete',
|
||||
total: 2.0,
|
||||
payment_total: 1.0,
|
||||
completed_at: 1.days.ago
|
||||
)
|
||||
end
|
||||
|
||||
it 'calls OutstandingBalance#query' do
|
||||
allow(OutstandingBalance).to receive(:new).and_return(outstanding_balance)
|
||||
expect(outstanding_balance).to receive(:query)
|
||||
|
||||
complete_orders_with_balance.query
|
||||
end
|
||||
|
||||
it 'returns complete orders including their balance' do
|
||||
order = complete_orders_with_balance.query.first
|
||||
expect(order[:balance_value]).to eq(-1.0)
|
||||
end
|
||||
|
||||
it 'sorts them by their completed_at with the most recent first' do
|
||||
orders = complete_orders_with_balance.query
|
||||
expect(orders.pluck(:id)).to eq([other_order.id, order.id])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the user has no complete orders' do
|
||||
let(:order) { create(:order) }
|
||||
|
||||
it 'calls OutstandingBalance' do
|
||||
allow(OutstandingBalance).to receive(:new).and_return(outstanding_balance)
|
||||
expect(outstanding_balance).to receive(:query)
|
||||
|
||||
complete_orders_with_balance.query
|
||||
end
|
||||
|
||||
it 'returns an empty array' do
|
||||
order = complete_orders_with_balance.query
|
||||
expect(order).to be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -9,6 +9,14 @@ describe CustomersWithBalance do
|
||||
let(:customer) { create(:customer) }
|
||||
let(:total) { 200.00 }
|
||||
let(:order_total) { 100.00 }
|
||||
let(:outstanding_balance) { instance_double(OutstandingBalance) }
|
||||
|
||||
it 'calls CustomersWithBalance#statement' do
|
||||
allow(OutstandingBalance).to receive(:new).and_return(outstanding_balance)
|
||||
expect(outstanding_balance).to receive(:statement)
|
||||
|
||||
customers_with_balance.query
|
||||
end
|
||||
|
||||
context 'when orders are in cart state' do
|
||||
before do
|
||||
@@ -61,9 +69,9 @@ describe CustomersWithBalance do
|
||||
context 'when no orders where paid' do
|
||||
before do
|
||||
order = create(:order, customer: customer, total: order_total, payment_total: 0)
|
||||
order.update_attribute(:state, 'checkout')
|
||||
order.update_attribute(:state, 'complete')
|
||||
order = create(:order, customer: customer, total: order_total, payment_total: 0)
|
||||
order.update_attribute(:state, 'checkout')
|
||||
order.update_attribute(:state, 'complete')
|
||||
end
|
||||
|
||||
it 'returns the customer balance' do
|
||||
@@ -77,9 +85,9 @@ describe CustomersWithBalance do
|
||||
|
||||
before do
|
||||
order = create(:order, customer: customer, total: order_total, payment_total: 0)
|
||||
order.update_attribute(:state, 'checkout')
|
||||
order.update_attribute(:state, 'complete')
|
||||
order = create(:order, customer: customer, total: order_total, payment_total: payment_total)
|
||||
order.update_attribute(:state, 'checkout')
|
||||
order.update_attribute(:state, 'complete')
|
||||
end
|
||||
|
||||
it 'returns the customer balance' do
|
||||
@@ -94,7 +102,7 @@ describe CustomersWithBalance do
|
||||
|
||||
before do
|
||||
order = create(:order, customer: customer, total: order_total, payment_total: 0)
|
||||
order.update_attribute(:state, 'checkout')
|
||||
order.update_attribute(:state, 'complete')
|
||||
create(
|
||||
:order,
|
||||
customer: customer,
|
||||
@@ -115,7 +123,7 @@ describe CustomersWithBalance do
|
||||
|
||||
before do
|
||||
order = create(:order, customer: customer, total: order_total, payment_total: 0)
|
||||
order.update_attribute(:state, 'checkout')
|
||||
order.update_attribute(:state, 'complete')
|
||||
order = create(:order, customer: customer, total: order_total, payment_total: payment_total)
|
||||
order.update_attribute(:state, 'resumed')
|
||||
end
|
||||
@@ -131,7 +139,7 @@ describe CustomersWithBalance do
|
||||
|
||||
before do
|
||||
order = create(:order, customer: customer, total: order_total, payment_total: 0)
|
||||
order.update_attribute(:state, 'checkout')
|
||||
order.update_attribute(:state, 'complete')
|
||||
order = create(:order, customer: customer, total: order_total, payment_total: payment_total)
|
||||
order.update_attribute(:state, 'payment')
|
||||
end
|
||||
@@ -147,7 +155,7 @@ describe CustomersWithBalance do
|
||||
|
||||
before do
|
||||
order = create(:order, customer: customer, total: order_total, payment_total: 0)
|
||||
order.update_attribute(:state, 'checkout')
|
||||
order.update_attribute(:state, 'complete')
|
||||
order = create(:order, customer: customer, total: order_total, payment_total: payment_total)
|
||||
order.update_attribute(:state, 'awaiting_return')
|
||||
end
|
||||
@@ -164,7 +172,7 @@ describe CustomersWithBalance do
|
||||
|
||||
before do
|
||||
order = create(:order, customer: customer, total: order_total, payment_total: 0)
|
||||
order.update_attribute(:state, 'checkout')
|
||||
order.update_attribute(:state, 'complete')
|
||||
order = create(:order, customer: customer, total: order_total, payment_total: payment_total)
|
||||
order.update_attribute(:state, 'returned')
|
||||
end
|
||||
197
spec/queries/outstanding_balance_spec.rb
Normal file
197
spec/queries/outstanding_balance_spec.rb
Normal file
@@ -0,0 +1,197 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe OutstandingBalance do
|
||||
let(:outstanding_balance) { described_class.new(relation) }
|
||||
|
||||
describe '#statement' do
|
||||
let(:relation) { Spree::Order.none }
|
||||
|
||||
it 'returns the CASE statement necessary to compute the order balance' do
|
||||
normalized_sql_statement = normalize(outstanding_balance.statement)
|
||||
|
||||
expect(normalized_sql_statement).to eq(normalize(<<-SQL))
|
||||
CASE WHEN state IN ('canceled', 'returned') THEN payment_total
|
||||
WHEN state IS NOT NULL THEN payment_total - total
|
||||
ELSE 0 END
|
||||
SQL
|
||||
end
|
||||
|
||||
def normalize(sql)
|
||||
sql.strip_heredoc.gsub("\n", '').squeeze(' ')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#query' do
|
||||
let(:relation) { Spree::Order.all }
|
||||
let(:total) { 200.00 }
|
||||
let(:order_total) { 100.00 }
|
||||
|
||||
context 'when orders are in cart state' do
|
||||
before do
|
||||
create(:order, total: order_total, payment_total: 0, state: 'cart')
|
||||
create(:order, total: order_total, payment_total: 0, state: 'cart')
|
||||
end
|
||||
|
||||
it 'returns the order balance' do
|
||||
order = outstanding_balance.query.first
|
||||
expect(order.balance_value).to eq(-order_total)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when orders are in address state' do
|
||||
before do
|
||||
create(:order, total: order_total, payment_total: 0, state: 'address')
|
||||
create(:order, total: order_total, payment_total: 50, state: 'address')
|
||||
end
|
||||
|
||||
it 'returns the order balance' do
|
||||
order = outstanding_balance.query.first
|
||||
expect(order.balance_value).to eq(-order_total)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when orders are in delivery state' do
|
||||
before do
|
||||
create(:order, total: order_total, payment_total: 0, state: 'delivery')
|
||||
create(:order, total: order_total, payment_total: 50, state: 'delivery')
|
||||
end
|
||||
|
||||
it 'returns the order balance' do
|
||||
order = outstanding_balance.query.first
|
||||
expect(order.balance_value).to eq(-order_total)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when orders are in payment state' do
|
||||
before do
|
||||
create(:order, total: order_total, payment_total: 0, state: 'payment')
|
||||
create(:order, total: order_total, payment_total: 50, state: 'payment')
|
||||
end
|
||||
|
||||
it 'returns the order balance' do
|
||||
order = outstanding_balance.query.first
|
||||
expect(order.balance_value).to eq(-order_total)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when no orders where paid' do
|
||||
before do
|
||||
order = create(:order, total: order_total, payment_total: 0)
|
||||
order.update_attribute(:state, 'complete')
|
||||
order = create(:order, total: order_total, payment_total: 0)
|
||||
order.update_attribute(:state, 'complete')
|
||||
end
|
||||
|
||||
it 'returns the customer balance' do
|
||||
order = outstanding_balance.query.first
|
||||
expect(order.balance_value).to eq(-order_total)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when an order was paid' do
|
||||
let(:payment_total) { order_total }
|
||||
|
||||
before do
|
||||
order = create(:order, total: order_total, payment_total: 0)
|
||||
order.update_attribute(:state, 'complete')
|
||||
order = create(:order, total: order_total, payment_total: payment_total)
|
||||
order.update_attribute(:state, 'complete')
|
||||
end
|
||||
|
||||
it 'returns the customer balance' do
|
||||
order = outstanding_balance.query.first
|
||||
expect(order.balance_value).to eq(payment_total - 200.0)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when an order is canceled' do
|
||||
let(:payment_total) { order_total }
|
||||
let(:non_canceled_orders_total) { order_total }
|
||||
|
||||
before do
|
||||
create(:order, total: order_total, payment_total: order_total, state: 'canceled')
|
||||
order = create(:order, total: order_total, payment_total: 0)
|
||||
order.update_attribute(:state, 'complete')
|
||||
end
|
||||
|
||||
it 'returns the customer balance' do
|
||||
order = outstanding_balance.query.first
|
||||
expect(order.balance_value).to eq(payment_total)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when an order is resumed' do
|
||||
let(:payment_total) { order_total }
|
||||
|
||||
before do
|
||||
order = create(:order, total: order_total, payment_total: 0)
|
||||
order.update_attribute(:state, 'complete')
|
||||
order = create(:order, total: order_total, payment_total: payment_total)
|
||||
order.update_attribute(:state, 'resumed')
|
||||
end
|
||||
|
||||
it 'returns the customer balance' do
|
||||
order = outstanding_balance.query.first
|
||||
expect(order.balance_value).to eq(payment_total - 200.0)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when an order is in payment' do
|
||||
let(:payment_total) { order_total }
|
||||
|
||||
before do
|
||||
order = create(:order, total: order_total, payment_total: 0)
|
||||
order.update_attribute(:state, 'complete')
|
||||
order = create(:order, total: order_total, payment_total: payment_total)
|
||||
order.update_attribute(:state, 'payment')
|
||||
end
|
||||
|
||||
it 'returns the customer balance' do
|
||||
order = outstanding_balance.query.first
|
||||
expect(order.balance_value).to eq(payment_total - 200.0)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when an order is awaiting_return' do
|
||||
let(:payment_total) { order_total }
|
||||
|
||||
before do
|
||||
order = create(:order, total: order_total, payment_total: 0)
|
||||
order.update_attribute(:state, 'complete')
|
||||
order = create(:order, total: order_total, payment_total: payment_total)
|
||||
order.update_attribute(:state, 'awaiting_return')
|
||||
end
|
||||
|
||||
it 'returns the customer balance' do
|
||||
order = outstanding_balance.query.first
|
||||
expect(order.balance_value).to eq(payment_total - 200.0)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when an order is returned' do
|
||||
let(:payment_total) { order_total }
|
||||
let(:non_returned_orders_total) { order_total }
|
||||
|
||||
before do
|
||||
order = create(:order, total: order_total, payment_total: payment_total)
|
||||
order.update_attribute(:state, 'returned')
|
||||
order = create(:order, total: order_total, payment_total: 0)
|
||||
order.update_attribute(:state, 'complete')
|
||||
end
|
||||
|
||||
it 'returns the customer balance' do
|
||||
order = outstanding_balance.query.first
|
||||
expect(order.balance_value).to eq(payment_total)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there are no orders' do
|
||||
it 'returns the order balance' do
|
||||
orders = outstanding_balance.query
|
||||
expect(orders).to be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -6,21 +6,55 @@ describe Api::OrderSerializer do
|
||||
let(:serializer) { Api::OrderSerializer.new order }
|
||||
let(:order) { create(:completed_order_with_totals) }
|
||||
|
||||
let!(:completed_payment) { create(:payment, order: order, state: 'completed', amount: order.total - 1) }
|
||||
let!(:payment) { create(:payment, order: order, state: 'checkout', amount: 123.45) }
|
||||
describe '#serializable_hash' do
|
||||
let!(:completed_payment) do
|
||||
create(:payment, order: order, state: 'completed', amount: order.total - 1)
|
||||
end
|
||||
let!(:payment) { create(:payment, order: order, state: 'checkout', amount: 123.45) }
|
||||
|
||||
it "serializes an order" do
|
||||
expect(serializer.to_json).to match order.number.to_s
|
||||
it "serializes an order" do
|
||||
expect(serializer.serializable_hash[:number]).to eq(order.number)
|
||||
end
|
||||
|
||||
it "convert the state attributes to translatable keys" do
|
||||
hash = serializer.serializable_hash
|
||||
|
||||
expect(hash[:state]).to eq("complete")
|
||||
expect(hash[:payment_state]).to eq("balance_due")
|
||||
end
|
||||
|
||||
it "only serializes completed payments" do
|
||||
hash = serializer.serializable_hash
|
||||
|
||||
expect(hash[:payments].first[:amount]).to eq(completed_payment.amount)
|
||||
end
|
||||
end
|
||||
|
||||
it "convert the state attributes to translatable keys" do
|
||||
# byebug if serializer.to_json =~ /balance_due/
|
||||
expect(serializer.to_json).to match "complete"
|
||||
expect(serializer.to_json).to match "balance_due"
|
||||
end
|
||||
describe '#outstanding_balance' do
|
||||
context 'when the customer_balance feature is enabled' do
|
||||
before do
|
||||
allow(OpenFoodNetwork::FeatureToggle)
|
||||
.to receive(:enabled?).with(:customer_balance, order.user) { true }
|
||||
|
||||
it "only serializes completed payments" do
|
||||
expect(serializer.to_json).to match completed_payment.amount.to_s
|
||||
expect(serializer.to_json).to_not match payment.amount.to_s
|
||||
allow(order).to receive(:balance_value).and_return(-1.23)
|
||||
end
|
||||
|
||||
it "returns the object's balance_value from the users perspective" do
|
||||
expect(serializer.serializable_hash[:outstanding_balance]).to eq(1.23)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the customer_balance is not enabled' do
|
||||
before do
|
||||
allow(OpenFoodNetwork::FeatureToggle)
|
||||
.to receive(:enabled?).with(:customer_balance, order.user) { false }
|
||||
|
||||
allow(order).to receive(:outstanding_balance).and_return(123.0)
|
||||
end
|
||||
|
||||
it 'calls #outstanding_balance on the object' do
|
||||
expect(serializer.serializable_hash[:outstanding_balance]).to eq(123.0)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user