311 lines
8.3 KiB
Elixir
311 lines
8.3 KiB
Elixir
|
|
defmodule SimpleshopTheme.ShippingTest do
|
||
|
|
use SimpleshopTheme.DataCase, async: false
|
||
|
|
|
||
|
|
alias SimpleshopTheme.Shipping
|
||
|
|
alias SimpleshopTheme.Shipping.ShippingRate
|
||
|
|
|
||
|
|
import SimpleshopTheme.ProductsFixtures
|
||
|
|
|
||
|
|
describe "upsert_rates/2" do
|
||
|
|
test "inserts new rates" do
|
||
|
|
conn = provider_connection_fixture()
|
||
|
|
|
||
|
|
rates = [
|
||
|
|
%{
|
||
|
|
blueprint_id: 100,
|
||
|
|
print_provider_id: 200,
|
||
|
|
country_code: "GB",
|
||
|
|
first_item_cost: 450,
|
||
|
|
additional_item_cost: 100,
|
||
|
|
currency: "GBP"
|
||
|
|
},
|
||
|
|
%{
|
||
|
|
blueprint_id: 100,
|
||
|
|
print_provider_id: 200,
|
||
|
|
country_code: "US",
|
||
|
|
first_item_cost: 650,
|
||
|
|
additional_item_cost: 150,
|
||
|
|
currency: "USD"
|
||
|
|
}
|
||
|
|
]
|
||
|
|
|
||
|
|
assert {:ok, 2} = Shipping.upsert_rates(conn.id, rates)
|
||
|
|
assert Repo.aggregate(ShippingRate, :count) == 2
|
||
|
|
end
|
||
|
|
|
||
|
|
test "replaces existing rates on conflict" do
|
||
|
|
conn = provider_connection_fixture()
|
||
|
|
|
||
|
|
rates = [
|
||
|
|
%{
|
||
|
|
blueprint_id: 100,
|
||
|
|
print_provider_id: 200,
|
||
|
|
country_code: "GB",
|
||
|
|
first_item_cost: 450,
|
||
|
|
additional_item_cost: 100,
|
||
|
|
currency: "GBP"
|
||
|
|
}
|
||
|
|
]
|
||
|
|
|
||
|
|
{:ok, 1} = Shipping.upsert_rates(conn.id, rates)
|
||
|
|
|
||
|
|
updated_rates = [
|
||
|
|
%{
|
||
|
|
blueprint_id: 100,
|
||
|
|
print_provider_id: 200,
|
||
|
|
country_code: "GB",
|
||
|
|
first_item_cost: 550,
|
||
|
|
additional_item_cost: 200,
|
||
|
|
currency: "GBP"
|
||
|
|
}
|
||
|
|
]
|
||
|
|
|
||
|
|
{:ok, 1} = Shipping.upsert_rates(conn.id, updated_rates)
|
||
|
|
|
||
|
|
assert Repo.aggregate(ShippingRate, :count) == 1
|
||
|
|
rate = Repo.one(ShippingRate)
|
||
|
|
assert rate.first_item_cost == 550
|
||
|
|
assert rate.additional_item_cost == 200
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
describe "get_rate/3" do
|
||
|
|
test "returns rate when it exists" do
|
||
|
|
conn = provider_connection_fixture()
|
||
|
|
|
||
|
|
{:ok, _} =
|
||
|
|
Shipping.upsert_rates(conn.id, [
|
||
|
|
%{
|
||
|
|
blueprint_id: 100,
|
||
|
|
print_provider_id: 200,
|
||
|
|
country_code: "GB",
|
||
|
|
first_item_cost: 450,
|
||
|
|
additional_item_cost: 100,
|
||
|
|
currency: "GBP"
|
||
|
|
}
|
||
|
|
])
|
||
|
|
|
||
|
|
rate = Shipping.get_rate(100, 200, "GB")
|
||
|
|
assert rate.first_item_cost == 450
|
||
|
|
assert rate.country_code == "GB"
|
||
|
|
end
|
||
|
|
|
||
|
|
test "returns nil when no rate exists" do
|
||
|
|
assert Shipping.get_rate(999, 999, "XX") == nil
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
describe "calculate_for_cart/2" do
|
||
|
|
test "returns {:ok, 0} for empty cart" do
|
||
|
|
assert {:ok, 0} = Shipping.calculate_for_cart([], "GB")
|
||
|
|
end
|
||
|
|
|
||
|
|
test "calculates shipping for single item" do
|
||
|
|
conn = provider_connection_fixture()
|
||
|
|
|
||
|
|
product =
|
||
|
|
product_fixture(%{
|
||
|
|
provider_connection: conn,
|
||
|
|
provider_data: %{"blueprint_id" => 100, "print_provider_id" => 200}
|
||
|
|
})
|
||
|
|
|
||
|
|
variant = product_variant_fixture(%{product: product})
|
||
|
|
|
||
|
|
{:ok, _} =
|
||
|
|
Shipping.upsert_rates(conn.id, [
|
||
|
|
%{
|
||
|
|
blueprint_id: 100,
|
||
|
|
print_provider_id: 200,
|
||
|
|
country_code: "GB",
|
||
|
|
first_item_cost: 450,
|
||
|
|
additional_item_cost: 100,
|
||
|
|
currency: "GBP"
|
||
|
|
}
|
||
|
|
])
|
||
|
|
|
||
|
|
cart_items = [%{variant_id: variant.id, quantity: 1}]
|
||
|
|
assert {:ok, 450} = Shipping.calculate_for_cart(cart_items, "GB")
|
||
|
|
end
|
||
|
|
|
||
|
|
test "calculates shipping for multiple quantities" do
|
||
|
|
conn = provider_connection_fixture()
|
||
|
|
|
||
|
|
product =
|
||
|
|
product_fixture(%{
|
||
|
|
provider_connection: conn,
|
||
|
|
provider_data: %{"blueprint_id" => 100, "print_provider_id" => 200}
|
||
|
|
})
|
||
|
|
|
||
|
|
variant = product_variant_fixture(%{product: product})
|
||
|
|
|
||
|
|
{:ok, _} =
|
||
|
|
Shipping.upsert_rates(conn.id, [
|
||
|
|
%{
|
||
|
|
blueprint_id: 100,
|
||
|
|
print_provider_id: 200,
|
||
|
|
country_code: "GB",
|
||
|
|
first_item_cost: 450,
|
||
|
|
additional_item_cost: 100,
|
||
|
|
currency: "GBP"
|
||
|
|
}
|
||
|
|
])
|
||
|
|
|
||
|
|
cart_items = [%{variant_id: variant.id, quantity: 3}]
|
||
|
|
# first_item_cost + 2 * additional_item_cost = 450 + 200 = 650
|
||
|
|
assert {:ok, 650} = Shipping.calculate_for_cart(cart_items, "GB")
|
||
|
|
end
|
||
|
|
|
||
|
|
test "returns error when no rates found" do
|
||
|
|
conn = provider_connection_fixture()
|
||
|
|
|
||
|
|
product =
|
||
|
|
product_fixture(%{
|
||
|
|
provider_connection: conn,
|
||
|
|
provider_data: %{"blueprint_id" => 100, "print_provider_id" => 200}
|
||
|
|
})
|
||
|
|
|
||
|
|
variant = product_variant_fixture(%{product: product})
|
||
|
|
|
||
|
|
cart_items = [%{variant_id: variant.id, quantity: 1}]
|
||
|
|
assert {:error, :rates_not_found} = Shipping.calculate_for_cart(cart_items, "XX")
|
||
|
|
end
|
||
|
|
|
||
|
|
test "groups items by print provider" do
|
||
|
|
conn = provider_connection_fixture()
|
||
|
|
|
||
|
|
product1 =
|
||
|
|
product_fixture(%{
|
||
|
|
provider_connection: conn,
|
||
|
|
provider_data: %{"blueprint_id" => 100, "print_provider_id" => 200}
|
||
|
|
})
|
||
|
|
|
||
|
|
product2 =
|
||
|
|
product_fixture(%{
|
||
|
|
provider_connection: conn,
|
||
|
|
provider_data: %{"blueprint_id" => 101, "print_provider_id" => 200}
|
||
|
|
})
|
||
|
|
|
||
|
|
variant1 = product_variant_fixture(%{product: product1})
|
||
|
|
variant2 = product_variant_fixture(%{product: product2})
|
||
|
|
|
||
|
|
{:ok, _} =
|
||
|
|
Shipping.upsert_rates(conn.id, [
|
||
|
|
%{
|
||
|
|
blueprint_id: 100,
|
||
|
|
print_provider_id: 200,
|
||
|
|
country_code: "GB",
|
||
|
|
first_item_cost: 450,
|
||
|
|
additional_item_cost: 100,
|
||
|
|
currency: "GBP"
|
||
|
|
},
|
||
|
|
%{
|
||
|
|
blueprint_id: 101,
|
||
|
|
print_provider_id: 200,
|
||
|
|
country_code: "GB",
|
||
|
|
first_item_cost: 500,
|
||
|
|
additional_item_cost: 150,
|
||
|
|
currency: "GBP"
|
||
|
|
}
|
||
|
|
])
|
||
|
|
|
||
|
|
cart_items = [
|
||
|
|
%{variant_id: variant1.id, quantity: 1},
|
||
|
|
%{variant_id: variant2.id, quantity: 1}
|
||
|
|
]
|
||
|
|
|
||
|
|
# Same provider: highest first_item_cost (500) + 1 additional item cost
|
||
|
|
assert {:ok, cost} = Shipping.calculate_for_cart(cart_items, "GB")
|
||
|
|
# 500 (highest first item) + one additional item cost (100 or 150)
|
||
|
|
assert cost in [600, 650]
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
describe "upsert_rates/3 with exchange rates" do
|
||
|
|
test "converts rates to GBP at sync time with buffer" do
|
||
|
|
conn = provider_connection_fixture()
|
||
|
|
exchange_rates = %{"USD" => 0.80}
|
||
|
|
|
||
|
|
rates = [
|
||
|
|
%{
|
||
|
|
blueprint_id: 100,
|
||
|
|
print_provider_id: 1,
|
||
|
|
country_code: "US",
|
||
|
|
first_item_cost: 1000,
|
||
|
|
additional_item_cost: 500,
|
||
|
|
currency: "USD"
|
||
|
|
}
|
||
|
|
]
|
||
|
|
|
||
|
|
{:ok, 1} = Shipping.upsert_rates(conn.id, rates, exchange_rates)
|
||
|
|
|
||
|
|
rate = Shipping.get_rate(100, 1, "US")
|
||
|
|
assert rate.currency == "GBP"
|
||
|
|
# 1000 USD cents * 0.80 rate * 1.05 buffer, ceil'd
|
||
|
|
assert rate.first_item_cost == 841
|
||
|
|
assert rate.additional_item_cost == 421
|
||
|
|
end
|
||
|
|
|
||
|
|
test "leaves GBP rates unconverted" do
|
||
|
|
conn = provider_connection_fixture()
|
||
|
|
exchange_rates = %{"USD" => 0.80}
|
||
|
|
|
||
|
|
rates = [
|
||
|
|
%{
|
||
|
|
blueprint_id: 100,
|
||
|
|
print_provider_id: 1,
|
||
|
|
country_code: "GB",
|
||
|
|
first_item_cost: 500,
|
||
|
|
additional_item_cost: 200,
|
||
|
|
currency: "GBP"
|
||
|
|
}
|
||
|
|
]
|
||
|
|
|
||
|
|
{:ok, 1} = Shipping.upsert_rates(conn.id, rates, exchange_rates)
|
||
|
|
|
||
|
|
rate = Shipping.get_rate(100, 1, "GB")
|
||
|
|
assert rate.currency == "GBP"
|
||
|
|
assert rate.first_item_cost == 500
|
||
|
|
assert rate.additional_item_cost == 200
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
describe "list_available_countries/0" do
|
||
|
|
test "returns distinct country codes" do
|
||
|
|
conn = provider_connection_fixture()
|
||
|
|
|
||
|
|
{:ok, _} =
|
||
|
|
Shipping.upsert_rates(conn.id, [
|
||
|
|
%{
|
||
|
|
blueprint_id: 100,
|
||
|
|
print_provider_id: 200,
|
||
|
|
country_code: "GB",
|
||
|
|
first_item_cost: 450,
|
||
|
|
additional_item_cost: 100,
|
||
|
|
currency: "GBP"
|
||
|
|
},
|
||
|
|
%{
|
||
|
|
blueprint_id: 100,
|
||
|
|
print_provider_id: 200,
|
||
|
|
country_code: "US",
|
||
|
|
first_item_cost: 650,
|
||
|
|
additional_item_cost: 150,
|
||
|
|
currency: "USD"
|
||
|
|
},
|
||
|
|
%{
|
||
|
|
blueprint_id: 101,
|
||
|
|
print_provider_id: 200,
|
||
|
|
country_code: "GB",
|
||
|
|
first_item_cost: 500,
|
||
|
|
additional_item_cost: 100,
|
||
|
|
currency: "GBP"
|
||
|
|
}
|
||
|
|
])
|
||
|
|
|
||
|
|
countries = Shipping.list_available_countries()
|
||
|
|
assert "GB" in countries
|
||
|
|
assert "US" in countries
|
||
|
|
assert length(countries) == 2
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|