Merge pull request #3337 from kristinalim/feature-enterprise_fees_report-order_based_calculator_bug

3283 [Enterprise Fee Summary] Fix values when calculator is order-based
This commit is contained in:
Pau Pérez Fabregat
2019-02-12 20:07:57 +01:00
committed by GitHub
15 changed files with 455 additions and 101 deletions

View File

@@ -2697,6 +2697,8 @@ See the %{link} to find out more about %{sitename}'s features and to start using
date_end_before_start_error: "must be after start"
parameter_not_allowed_error: "You are not authorized to use one or more selected filters for this report."
fee_calculated_on_transfer_through_all: "All"
fee_calculated_on_transfer_through_entire_orders: "Entire Orders through %{distributor}"
tax_category_various: "Various"
fee_type:
payment_method: "Payment Transaction"
shipping_method: "Shipment"

View File

@@ -0,0 +1,27 @@
# This module provides EnterpriseFeeSummary::Scope DB result to report mappings for coordinator fees
# in an order cycle.
module OrderManagement
module Reports
module EnterpriseFeeSummary
module DataRepresentations
class CoordinatorFee
include UsingEnterpriseFee
def fee_calculated_on_transfer_through_name
i18n_translate("fee_calculated_on_transfer_through_all")
end
def tax_category_name
return data["tax_category_name"] if data["tax_category_name"].present?
i18n_translate("tax_category_various") if inherits_tax_category?
end
def inherits_tax_category?
data["enterprise_fee_inherits_tax_category"] == "t"
end
end
end
end
end
end

View File

@@ -0,0 +1,23 @@
# This module provides EnterpriseFeeSummary::Scope DB result to report mappings for exchange fees
# that use order-based calculators.
module OrderManagement
module Reports
module EnterpriseFeeSummary
module DataRepresentations
class ExchangeOrderFee
include UsingEnterpriseFee
def fee_calculated_on_transfer_through_name
i18n_translate("fee_calculated_on_transfer_through_entire_orders",
distributor: data["adjustment_source_distributor_name"])
end
def tax_category_name
data["tax_category_name"] || i18n_translate("tax_category_various")
end
end
end
end
end
end

View File

@@ -0,0 +1,22 @@
# This module provides EnterpriseFeeSummary::Scope DB result to report mappings for incoming
# exchange fees that use line item -based calculators.
module OrderManagement
module Reports
module EnterpriseFeeSummary
module DataRepresentations
class IncomingExchangeLineItemFee
include UsingEnterpriseFee
def fee_calculated_on_transfer_through_name
data["incoming_exchange_enterprise_name"]
end
def tax_category_name
data["tax_category_name"] || data["product_tax_category_name"]
end
end
end
end
end
end

View File

@@ -0,0 +1,22 @@
# This module provides EnterpriseFeeSummary::Scope DB result to report mappings for outgoing
# exchange fees that use line item -based calculators.
module OrderManagement
module Reports
module EnterpriseFeeSummary
module DataRepresentations
class OutgoingExchangeLineItemFee
include UsingEnterpriseFee
def fee_calculated_on_transfer_through_name
data["outgoing_exchange_enterprise_name"]
end
def tax_category_name
data["tax_category_name"] || data["product_tax_category_name"]
end
end
end
end
end
end

View File

@@ -0,0 +1,38 @@
# This module provides EnterpriseFeeSummary::Scope DB result to report mappings for payment method
# fees.
module OrderManagement
module Reports
module EnterpriseFeeSummary
module DataRepresentations
class PaymentMethodFee
include WithI18n
attr_reader :data
def initialize(data)
@data = data
end
def fee_type
i18n_translate("fee_type.payment_method")
end
def enterprise_name
data["hub_name"]
end
def fee_name
data["payment_method_name"]
end
def fee_placement; end
def fee_calculated_on_transfer_through_name; end
def tax_category_name; end
end
end
end
end
end

View File

@@ -0,0 +1,40 @@
# This module provides EnterpriseFeeSummary::Scope DB result to report mappings for shipping method
# fees.
module OrderManagement
module Reports
module EnterpriseFeeSummary
module DataRepresentations
class ShippingMethodFee
include WithI18n
attr_reader :data
def initialize(data)
@data = data
end
def fee_type
i18n_translate("fee_type.shipping_method")
end
def enterprise_name
data["hub_name"]
end
def fee_name
data["shipping_method_name"]
end
def fee_placement; end
def fee_calculated_on_transfer_through_name; end
def tax_category_name
i18n_translate("tax_category_name.shipping_instance_rate")
end
end
end
end
end
end

View File

@@ -0,0 +1,40 @@
# Different EnterpriseFeeSummary::Scope DB result attributes are checked when dealing with
# enterprise fees that are attached to an order cycle in different ways.
#
# This module provides DB result to report mappings that are common among all rows for enterprise
# fees. These mappings are not complete and should be supplemented with mappings that are specific
# to the way that the enterprise fee is attached to the order cycle.
module OrderManagement
module Reports
module EnterpriseFeeSummary
module DataRepresentations
module UsingEnterpriseFee
include WithI18n
attr_reader :data
def initialize(data)
@data = data
end
def fee_type
data["fee_type"].try(:capitalize)
end
def enterprise_name
data["enterprise_name"]
end
def fee_name
data["fee_name"]
end
def fee_placement
i18n_translate("fee_placements.#{data['placement_enterprise_role']}")
end
end
end
end
end
end

View File

@@ -0,0 +1,15 @@
module OrderManagement
module Reports
module EnterpriseFeeSummary
module DataRepresentations
module WithI18n
private
def i18n_translate(translation_key, options = {})
I18n.t("order_management.reports.enterprise_fee_summary.#{translation_key}", options)
end
end
end
end
end
end

View File

@@ -1,87 +0,0 @@
module OrderManagement
module Reports
module EnterpriseFeeSummary
class EnterpriseFeeTypeTotalSummarizer
attr_accessor :data
def initialize(data)
@data = data
end
def fee_type
if for_payment_method?
i18n_translate("fee_type.payment_method")
elsif for_shipping_method?
i18n_translate("fee_type.shipping_method")
else
data["fee_type"].try(:capitalize)
end
end
def enterprise_name
if for_payment_method?
data["hub_name"]
elsif for_shipping_method?
data["hub_name"]
else
data["enterprise_name"]
end
end
def fee_name
if for_payment_method?
data["payment_method_name"]
elsif for_shipping_method?
data["shipping_method_name"]
else
data["fee_name"]
end
end
def customer_name
data["customer_name"]
end
def fee_placement
return if for_payment_method? || for_shipping_method?
i18n_translate("fee_placements.#{data['placement_enterprise_role']}")
end
def fee_calculated_on_transfer_through_name
return if for_payment_method? || for_shipping_method?
transfer_through_all_string = i18n_translate("fee_calculated_on_transfer_through_all")
data["incoming_exchange_enterprise_name"] || data["outgoing_exchange_enterprise_name"] ||
(transfer_through_all_string if data["placement_enterprise_role"] == "coordinator")
end
def tax_category_name
return if for_payment_method?
return i18n_translate("tax_category_name.shipping_instance_rate") if for_shipping_method?
data["tax_category_name"] || data["product_tax_category_name"]
end
def total_amount
data["total_amount"]
end
private
def for_payment_method?
data["payment_method_name"].present?
end
def for_shipping_method?
data["shipping_method_name"].present?
end
def i18n_translate(translation_key)
I18n.t("order_management.reports.enterprise_fee_summary.#{translation_key}")
end
end
end
end
end

View File

@@ -25,7 +25,7 @@ module OrderManagement
def enterprise_fee_type_total_list
enterprise_fees_by_customer.map do |total_data|
summarizer = EnterpriseFeeTypeTotalSummarizer.new(total_data)
summarizer = Summarizer.new(total_data)
ReportData::EnterpriseFeeTypeTotal.new.tap do |total|
enterprise_fee_type_summarizer_to_total_attributes.each do |attribute|

View File

@@ -31,7 +31,8 @@ module OrderManagement
include_payment_fee_details
include_shipping_fee_details
include_enterprise_fee_details
include_line_item_details
include_order_source_details
include_line_item_source_details
include_incoming_exchange_details
include_outgoing_exchange_details
@@ -169,14 +170,38 @@ module OrderManagement
)
end
# If for line item - Use data only if spree_line_items.id is present
# If for order source
#
# Includes:
# * Source order
# * Distributor
def include_order_source_details
join_scope(
<<-JOIN_STRING.strip_heredoc
LEFT OUTER JOIN spree_orders AS adjustment_source_orders
ON (
spree_adjustments.source_type = 'Spree::Order'
AND adjustment_source_orders.id = spree_adjustments.source_id
)
JOIN_STRING
)
join_scope(
<<-JOIN_STRING.strip_heredoc
LEFT OUTER JOIN enterprises AS adjustment_source_distributors
ON (adjustment_source_distributors.id = adjustment_source_orders.distributor_id)
JOIN_STRING
)
end
# If for line item source - Use data only if spree_line_items.id is present
#
# Includes:
# * Line item
# * Variant
# * Product
# * Tax category of product, if enterprise fee tells to inherit
def include_line_item_details
def include_line_item_source_details
join_scope(
<<-JOIN_STRING.strip_heredoc
LEFT OUTER JOIN spree_line_items
@@ -316,7 +341,8 @@ module OrderManagement
group("enterprise_fees.id", "enterprises.id", "customers.id", "hubs.id",
"spree_payment_methods.id", "spree_shipping_methods.id",
"adjustment_metadata.enterprise_role", "spree_tax_categories.id",
"product_tax_categories.id", "incoming_exchange_enterprises.id",
"product_tax_categories.id", "spree_adjustments.source_type",
"adjustment_source_distributors.id", "incoming_exchange_enterprises.id",
"outgoing_exchange_enterprises.id")
end
end
@@ -331,8 +357,11 @@ module OrderManagement
enterprise_fees.fee_type AS fee_type, customers.name AS customer_name,
customers.email AS customer_email, enterprise_fees.fee_type AS fee_type,
enterprise_fees.name AS fee_name, spree_tax_categories.name AS tax_category_name,
enterprise_fees.inherits_tax_category AS enterprise_fee_inherits_tax_category,
product_tax_categories.name AS product_tax_category_name,
adjustment_metadata.enterprise_role AS placement_enterprise_role,
spree_adjustments.source_type AS adjustment_source_type,
adjustment_source_distributors.name AS adjustment_source_distributor_name,
incoming_exchange_enterprises.name AS incoming_exchange_enterprise_name,
outgoing_exchange_enterprises.name AS outgoing_exchange_enterprise_name
JOIN_STRING

View File

@@ -0,0 +1,76 @@
module OrderManagement
module Reports
module EnterpriseFeeSummary
class Summarizer
attr_reader :data
delegate :fee_type, :enterprise_name, :fee_name, :fee_placement,
:fee_calculated_on_transfer_through_name, :tax_category_name, to: :representation
def initialize(data)
@data = data
end
def customer_name
data["customer_name"]
end
def total_amount
data["total_amount"]
end
private
def representation
@representation ||= representation_klass.new(data)
end
def representation_klass
return DataRepresentations::PaymentMethodFee if for_payment_method?
return DataRepresentations::ShippingMethodFee if for_shipping_method?
enterprise_fee_adjustment_presentation_klass if for_enterprise_fee?
end
def enterprise_fee_adjustment_presentation_klass
return DataRepresentations::CoordinatorFee if for_coordinator_fee?
return DataRepresentations::ExchangeOrderFee if for_order_adjustment_source?
return unless for_line_item_adjustment_source?
return DataRepresentations::IncomingExchangeLineItemFee if for_incoming_exchange?
return DataRepresentations::OutgoingExchangeLineItemFee if for_outgoing_exchange?
end
def for_payment_method?
data["payment_method_name"].present?
end
def for_shipping_method?
data["shipping_method_name"].present?
end
def for_enterprise_fee?
data["fee_name"].present?
end
def for_coordinator_fee?
data["placement_enterprise_role"] == "coordinator"
end
def for_incoming_exchange?
data["placement_enterprise_role"] == "supplier"
end
def for_outgoing_exchange?
data["placement_enterprise_role"] == "distributor"
end
def for_order_adjustment_source?
data["adjustment_source_type"] == "Spree::Order"
end
def for_line_item_adjustment_source?
data["adjustment_source_type"] == "Spree::LineItem"
end
end
end
end
end

View File

@@ -124,9 +124,9 @@ describe OrderManagement::Reports::EnterpriseFeeSummary::ReportService do
["Payment Transaction", "Sample Distributor", "Sample Payment Method", "Sample Customer",
nil, nil, nil, "4.00"],
["Sales", "Sample Coordinator", "Coordinator Fee 2", "Another Customer",
"Coordinator", "All", "Sample Product Tax", "1024.00"],
"Coordinator", "All", "Various", "1024.00"],
["Sales", "Sample Coordinator", "Coordinator Fee 2", "Sample Customer",
"Coordinator", "All", "Sample Product Tax", "2048.00"],
"Coordinator", "All", "Various", "2048.00"],
["Sales", "Sample Distributor", "Distributor Fee 2", "Another Customer",
"Outgoing", "Sample Distributor", "Sample Product Tax", "8.00"],
["Sales", "Sample Distributor", "Distributor Fee 2", "Sample Customer",
@@ -206,6 +206,98 @@ describe OrderManagement::Reports::EnterpriseFeeSummary::ReportService do
end
end
end
context "with order-based enterprise fee calculator" do
let!(:producer_fee) do
tax_category = create(:tax_category, name: "Producer Tax A")
create(:enterprise_fee, :flat_rate, name: "Producer Fee A", enterprise: producer,
fee_type: "sales", tax_category: tax_category,
amount: 10)
end
let!(:coordinator_fee) do
tax_category = create(:tax_category, name: "Coordinator Tax A")
create(:enterprise_fee, :flat_rate, name: "Coordinator Fee A", enterprise: coordinator,
fee_type: "admin", tax_category: tax_category,
amount: 15)
end
let!(:coordinator_fee_inheriting_product_tax_category) do
create(:enterprise_fee, :flat_rate, name: "Coordinator Fee B", enterprise: coordinator,
fee_type: "admin", inherits_tax_category: true,
amount: 20)
end
let!(:coordinator_fee_without_tax) do
create(:enterprise_fee, :flat_rate, name: "Coordinator Fee C", enterprise: coordinator,
fee_type: "admin", inherits_tax_category: false,
amount: 25)
end
let!(:distributor_fee) do
tax_category = create(:tax_category, name: "Distributor Tax A")
create(:enterprise_fee, :flat_rate, name: "Distributor Fee A", enterprise: distributor,
fee_type: "admin", inherits_tax_category: false,
amount: 30)
end
let!(:coordinator_fees) do
[
coordinator_fee,
coordinator_fee_inheriting_product_tax_category,
coordinator_fee_without_tax
]
end
let!(:order_cycle) do
create(:simple_order_cycle, coordinator: coordinator, coordinator_fees: coordinator_fees)
end
let!(:variant_incoming_exchange_fees) { [producer_fee, coordinator_fee, distributor_fee] }
let!(:variant_outgoing_exchange_fees) { [producer_fee, coordinator_fee, distributor_fee] }
let!(:variant) do
prepare_variant(incoming_exchange_fees: variant_incoming_exchange_fees,
outgoing_exchange_fees: variant_outgoing_exchange_fees)
end
let!(:customer_order) { prepare_order(customer: customer) }
it "fetches data correctly" do
totals = service.list
expect(totals.length).to eq(11)
entire_orders_text = i18n_translate("fee_calculated_on_transfer_through_entire_orders",
distributor: "Sample Distributor")
various_tax_categories_text = i18n_translate("tax_category_various")
expected_result = [
["Admin", "Sample Coordinator", "Coordinator Fee A", "Sample Customer",
"Coordinator", "All", "Coordinator Tax A", "15.00"],
["Admin", "Sample Coordinator", "Coordinator Fee A", "Sample Customer",
"Incoming", entire_orders_text, "Coordinator Tax A", "15.00"],
["Admin", "Sample Coordinator", "Coordinator Fee A", "Sample Customer",
"Outgoing", entire_orders_text, "Coordinator Tax A", "15.00"],
["Admin", "Sample Coordinator", "Coordinator Fee B", "Sample Customer",
"Coordinator", "All", various_tax_categories_text, "20.00"],
["Admin", "Sample Coordinator", "Coordinator Fee C", "Sample Customer",
"Coordinator", "All", nil, "25.00"],
["Admin", "Sample Distributor", "Distributor Fee A", "Sample Customer",
"Incoming", entire_orders_text, various_tax_categories_text, "30.00"],
["Admin", "Sample Distributor", "Distributor Fee A", "Sample Customer",
"Outgoing", entire_orders_text, various_tax_categories_text, "30.00"],
["Payment Transaction", "Sample Distributor", "Sample Payment Method", "Sample Customer",
nil, nil, nil, "2.00"],
["Sales", "Sample Producer", "Producer Fee A", "Sample Customer",
"Incoming", entire_orders_text, "Producer Tax A", "10.00"],
["Sales", "Sample Producer", "Producer Fee A", "Sample Customer",
"Outgoing", entire_orders_text, "Producer Tax A", "10.00"],
["Shipment", "Sample Distributor", "Sample Shipping Method", "Sample Customer",
nil, nil, "Platform Rate", "1.00"]
]
expected_result.each_with_index do |expected_attributes, row_index|
expect_total_attributes(totals[row_index], expected_attributes)
end
end
end
end
describe "filtering results based on permissions" do
@@ -488,6 +580,10 @@ describe OrderManagement::Reports::EnterpriseFeeSummary::ReportService do
# Helper methods for example group
def i18n_translate(translation_key, options = {})
I18n.t("order_management.reports.enterprise_fee_summary.#{translation_key}", options)
end
def expect_total_attributes(total, expected_attribute_list)
actual_attribute_list = [total.fee_type, total.enterprise_name, total.fee_name,
total.customer_name, total.fee_placement,

View File

@@ -1,12 +1,23 @@
attach_per_item_trait = proc do
trait :per_item do
transient { amount 1 }
calculator { build(:calculator_per_item, preferred_amount: amount) }
FactoryBot.define do
factory :calculator_flat_rate, class: Spree::Calculator::FlatRate do
preferred_amount { generate(:calculator_amount) }
end
end
FactoryBot.modify do
factory :payment_method, &attach_per_item_trait
factory :shipping_method, &attach_per_item_trait
factory :enterprise_fee, &attach_per_item_trait
attach_calculator_traits = proc do
trait :flat_rate do
transient { amount 1 }
calculator { build(:calculator_flat_rate, preferred_amount: amount) }
end
trait :per_item do
transient { amount 1 }
calculator { build(:calculator_per_item, preferred_amount: amount) }
end
end
factory :payment_method, &attach_calculator_traits
factory :shipping_method, &attach_calculator_traits
factory :enterprise_fee, &attach_calculator_traits
end