Skip to content

Commit

Permalink
Marketplace: Delivery constraints live on DeliveryArea
Browse files Browse the repository at this point in the history
- #1325
- #1136
- #1185

Allowing a `Marketplace` to specify it's delivery fees, constraints,
etc. and a `DeliveryArea` to override them was putting us in a bit of a
mess from "how does data even?!"

This consolidates everything onto `DeliveryArea`, yay!
  • Loading branch information
zspencer committed Apr 30, 2023
1 parent 1c89b6e commit fede865
Show file tree
Hide file tree
Showing 18 changed files with 61 additions and 57 deletions.
2 changes: 2 additions & 0 deletions app/furniture/marketplace/cart.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ class Cart < Record

belongs_to :shopper, inverse_of: :carts

belongs_to :delivery_area, inverse_of: :carts, optional: true

has_many :cart_products, dependent: :destroy, inverse_of: :cart
has_many :products, through: :cart_products, inverse_of: :carts

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,18 @@ class Cart
class DeliveryExpectationsComponent < ApplicationComponent
attr_accessor :cart, :delivery_window, :order_by

def initialize(cart:, order_by: cart.marketplace.order_by,
delivery_window: cart.marketplace.delivery_window, **kwargs)
def initialize(cart:, order_by: cart.delivery_area&.order_by,
delivery_window: cart.delivery_area&.delivery_window, **kwargs)
super(**kwargs)

self.cart = cart
self.delivery_window = delivery_window
self.order_by = order_by
end

def render?
cart.delivery_area.present?
end
end
end
end
8 changes: 3 additions & 5 deletions app/furniture/marketplace/checkout.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ class Checkout < Model
location(parent: :cart)
include ActiveModel::Validations
attr_accessor :cart
delegate :shopper, :marketplace, :persisted?, to: :cart
delegate :shopper, :delivery_fee, :marketplace, :persisted?, to: :cart

# It would be nice to validate instead the presence of :ordered_products, but my attempts at this raise:
# ActiveRecord::HasManyThroughCantAssociateThroughHasOneOrManyReflection:
Expand All @@ -25,9 +25,7 @@ def create_stripe_session(success_url:, cancel_url:)
})
end

private

def stripe_line_items
private def stripe_line_items
return [] if cart.blank?

stripe_cart_products_line_items + stripe_delivery_fee_line_items + stripe_taxes_line_items
Expand All @@ -51,7 +49,7 @@ def stripe_line_items
{quantity: 1,
price_data: {
currency: "USD",
unit_amount: marketplace.delivery_fee_cents,
unit_amount: delivery_fee,
product_data: {name: "Delivery"}
}}
]
Expand Down
2 changes: 1 addition & 1 deletion app/furniture/marketplace/delivery.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def delivery_window
alias_method :window, :delivery_window

def fee
delivery_area&.price.presence || marketplace&.delivery_fee.presence
delivery_area&.price.presence || 0
end

def details_filled_in?
Expand Down
1 change: 1 addition & 0 deletions app/furniture/marketplace/delivery_area.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ class DeliveryArea < Record

belongs_to :marketplace, inverse_of: :delivery_areas
has_many :orders, inverse_of: :delivery_area
has_many :carts, inverse_of: :delivery_area
has_many :deliveries, inverse_of: :delivery_area

attribute :delivery_window, ::Marketplace::Delivery::WindowType.new
Expand Down
2 changes: 1 addition & 1 deletion app/furniture/marketplace/delivery_area_component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def price
end

def example_cart
delivery_area.marketplace.carts.new
delivery_area.marketplace.carts.new(delivery_area: delivery_area)
end

delegate :order_by, to: :delivery_area
Expand Down
5 changes: 1 addition & 4 deletions app/furniture/marketplace/marketplace.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
class Marketplace
class Marketplace < Furniture
location(parent: :room)
default_scope { where(furniture_kind: "marketplace") }

has_many :products, inverse_of: :marketplace, dependent: :destroy
has_many :carts, inverse_of: :marketplace, dependent: :destroy
Expand All @@ -11,11 +12,7 @@ class Marketplace < Furniture
has_many :tax_rates, inverse_of: :marketplace
has_many :delivery_areas, inverse_of: :marketplace, dependent: :destroy

setting :delivery_fee_cents, default: 0
monetize :delivery_fee_cents
setting :delivery_window
setting :notify_emails
setting :order_by
setting :stripe_account
alias_method :vendor_stripe_account, :stripe_account
setting :stripe_webhook_endpoint
Expand Down
4 changes: 1 addition & 3 deletions app/furniture/marketplace/marketplaces/_form.html.erb
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
<div class="mt-3">
<%= form_with model: marketplace.location do |f| %>
<%= render "money_field", { attribute: :delivery_fee, form: f, min: 0, step: 0.01} %>
<%= render "text_field", { attribute: :notify_emails, form: f } %>
<%= render "text_field", { attribute: :order_by, form: f } %>
<%= render "text_field", { attribute: :delivery_window, form: f } %>

<%= f.submit %>
<% end %>
</div>
6 changes: 4 additions & 2 deletions app/furniture/marketplace/order.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,17 @@ def delivery
becomes(Delivery)
end

delegate :delivery_fee, to: :marketplace
def delivery_fee
delivery_area&.price
end
delegate :delivery_window, to: :delivery_area, allow_nil: true

def marketplace_name
marketplace.room.name
end

def price_total
product_total + delivery_fee + tax_total
[product_total, delivery_fee, tax_total].compact.sum
end
end
end
Binary file modified docs/erd.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 0 additions & 5 deletions spec/factories/furniture/marketplace.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,6 @@
notify_emails { Array.new((1..3).to_a.sample) { Faker::Internet.safe_email }.join(",") }
end

trait :with_delivery_fees do
delivery_fee_cents { (10_00..25_00).to_a.sample }
end

trait :with_delivery_areas do
transient do
delivery_area_quantity { 1 }
Expand All @@ -42,7 +38,6 @@
trait :full do
with_tax_rates
with_delivery_areas
with_delivery_fees
with_notify_emails
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,32 @@
context "when the cart does not have a `delivery_area`" do
let(:cart) { build(:marketplace_cart, marketplace: marketplace) }

context "when the `marketplace` has an `order_by` without a `delivery_window`" do
let(:marketplace) { build(:marketplace, order_by: "by 8AM") }
specify { expect(component.render?).to be_falsey } # rubocop:disable RSpec/PredicateMatcher
end

context "when the cart has a delivey area" do
let(:cart) { build(:marketplace_cart, delivery_area: delivery_area, marketplace: marketplace) }

context "when the `delivery_area` has an `order_by` without a `delivery_window`" do
let(:delivery_area) { build(:marketplace_delivery_area, marketplace: marketplace, order_by: "by 8AM") }

it { is_expected.to have_content("Order by 8AM") }
end

context "when the `marketplace` has a `delivery_window` without an `order_by`" do
let(:marketplace) { build(:marketplace, delivery_window: "at Noon") }
context "when the `delivery_area` has a `delivery_window` without an `order_by`" do
let(:delivery_area) { build(:marketplace_delivery_area, marketplace: marketplace, delivery_window: "at Noon") }

it { is_expected.to have_content("Orders are delivered at Noon", normalize_ws: true) }
end

context "when the `marketplace` has `delivery_window` and an `order_by`" do
let(:marketplace) { build(:marketplace, delivery_window: "at Noon", order_by: "by 8AM") }
context "when the `delivery_area` has `delivery_window` and an `order_by`" do
let(:delivery_area) { build(:marketplace_delivery_area, marketplace: marketplace, delivery_window: "at Noon", order_by: "by 8AM") }

it { is_expected.to have_content("Orders placed by 8AM are delivered at Noon", normalize_ws: true) }
end

context "when the `marketplace` has neither an `order_by` nor a `delivery_window`" do
let(:marketplace) { build(:marketplace) }
context "when the `delivery_area` has neither an `order_by` nor a `delivery_window`" do
let(:delivery_area) { build(:marketplace_delivery_area, marketplace: marketplace) }

it {
expect(output).to have_content("Delivers at your chosen time")
Expand Down
7 changes: 5 additions & 2 deletions spec/furniture/marketplace/cart_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,14 @@

it { is_expected.to belong_to(:shopper).inverse_of(:carts) }

it { is_expected.to belong_to(:delivery_area).inverse_of(:carts).optional }

describe "#price_total" do
subject(:price_total) { cart.price_total }

let(:marketplace) { create(:marketplace, delivery_fee_cents: 1200) }
let(:cart) { create(:marketplace_cart, marketplace: marketplace) }
let(:marketplace) { create(:marketplace) }
let(:delivery_area) { create(:marketplace_delivery_area, price_cents: 12_00) }
let(:cart) { create(:marketplace_cart, marketplace: marketplace, delivery_area: delivery_area) }
let(:product_a) { create(:marketplace_product, marketplace: cart.marketplace) }
let(:product_b) { create(:marketplace_product, marketplace: cart.marketplace, tax_rate_ids: [sales_tax.id]) }
let(:sales_tax) { create(:marketplace_tax_rate, marketplace: cart.marketplace, tax_rate: 5.0) }
Expand Down
1 change: 1 addition & 0 deletions spec/furniture/marketplace/delivery_area_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
RSpec.describe Marketplace::DeliveryArea, type: :model do
it { is_expected.to belong_to(:marketplace).inverse_of(:delivery_areas) }
it { is_expected.to have_many(:orders).inverse_of(:delivery_area) }
it { is_expected.to have_many(:carts).inverse_of(:delivery_area) }
it { is_expected.to have_many(:deliveries).inverse_of(:delivery_area) }
end
20 changes: 3 additions & 17 deletions spec/furniture/marketplace/delivery_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,10 @@
describe "#fee" do
subject(:fee) { delivery.fee }

context "when there is not a marketplace delivery fee or a delivery area delivery fee" do
let(:delivery_area) { build(:marketplace_delivery_area, price_cents: nil, marketplace: marketplace) }
context "when `price_cents` is nil" do
let(:delivery_area) { build(:marketplace_delivery_area, marketplace: marketplace, price_cents: nil) }

it { is_expected.to eq(0) }
end

context "when the marketplace has a delivery fee and the delivery area has a delivery fee" do
let(:marketplace) { build(:marketplace, delivery_fee_cents: 25_00) }
let(:delivery_area) { build(:marketplace_delivery_area, price_cents: 50_00, marketplace: marketplace) }

it { is_expected.to eq(delivery_area.price) }
end

context "when the marketplace has a delivery fee but the delivery area does not" do
let(:marketplace) { build(:marketplace, delivery_fee_cents: 25_00) }
let(:delivery_area) { build(:marketplace_delivery_area, price_cents: nil, marketplace: marketplace) }

it { is_expected.to eq(marketplace.delivery_fee) }
it { is_expected.to be_zero }
end
end

Expand Down
10 changes: 10 additions & 0 deletions spec/furniture/marketplace/marketplace_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,14 @@
specify { expect { marketplace.destroy }.not_to change(orders, :count) }
end
end

describe ".all" do
subject(:all) { described_class.all }

let!(:non_marketplace_furniture) { create(:journal) }
let!(:marketplace_furniture) { create(:marketplace) }

it { is_expected.not_to include(non_marketplace_furniture) }
it { is_expected.to include(marketplace_furniture) }
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@
before { sign_in(space, member) }

it "updates the attributes" do
put polymorphic_path(marketplace.location), params: {marketplace: {delivery_fee: 50.00, delivery_window: "Tomorrow, mahhhhn...", order_by: "10AM"}}
marketplace_attributes = attributes_for(:marketplace, notify_emails: "notify@example.com")
put polymorphic_path(marketplace.location), params: {marketplace: marketplace_attributes}
marketplace.reload

expect(marketplace.reload.delivery_fee_cents).to eq(50_00)
expect(marketplace.reload.delivery_window).to eq("Tomorrow, mahhhhn...")
expect(marketplace.reload.order_by).to eq("10AM")
expect(marketplace.notify_emails).to eq(marketplace_attributes[:notify_emails])
end
end
end
7 changes: 4 additions & 3 deletions spec/furniture/marketplace/order_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@
describe "#price_total" do
subject(:price_total) { order.price_total }

let(:marketplace) { create(:marketplace, delivery_fee_cents: 1200) }
let(:order) { create(:marketplace_order, marketplace: marketplace) }
let(:marketplace) { create(:marketplace) }
let(:delivery_area) { create(:marketplace_delivery_area, marketplace: marketplace, price_cents: 1200) }
let(:order) { create(:marketplace_order, marketplace: marketplace, delivery_area: delivery_area) }
let(:product_a) { create(:marketplace_product, marketplace: order.marketplace) }
let(:product_b) { create(:marketplace_product, marketplace: order.marketplace, tax_rate_ids: [sales_tax.id]) }
let(:sales_tax) { create(:marketplace_tax_rate, marketplace: order.marketplace, tax_rate: 5.0) }
Expand All @@ -24,7 +25,7 @@
order.ordered_products.create!(product: product_b, quantity: 2)
end

it { is_expected.to eql(product_a.price + product_b.price * 2 + marketplace.delivery_fee + (product_b.price * 2 * 0.05)) }
it { is_expected.to eql(product_a.price + product_b.price * 2 + delivery_area.price + (product_b.price * 2 * 0.05)) }
end

describe "#product_total" do
Expand Down

0 comments on commit fede865

Please sign in to comment.