Skip to content

Commit

Permalink
Marketplace: Collect Shoppers Delivery Address before checkout
Browse files Browse the repository at this point in the history
- #1136

While collecting the address via Stripe was reasonable at the time, if
we want to support dynamic pricing, we'll need the address ahead of
time.

This will also (theoretically) allow us to let people know when they are
outside of the `Distributor` delivery area.
  • Loading branch information
zspencer committed Mar 2, 2023
1 parent f0c17d7 commit 1f9dc06
Show file tree
Hide file tree
Showing 9 changed files with 134 additions and 35 deletions.
6 changes: 5 additions & 1 deletion app/furniture/marketplace/cart.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@ def product_total
end
end

delegate :delivery_fee, to: :marketplace
def delivery_fee
return marketplace.delivery_fee if delivery_address.present?

0
end

def price_total
product_total + delivery_fee
Expand Down
24 changes: 24 additions & 0 deletions app/furniture/marketplace/cart_policy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# frozen_string_literal: true

class Marketplace
class CartPolicy < ApplicationPolicy
alias_method :cart, :object
def permitted_attributes(_params = nil)
%i[delivery_address]
end

def create?
true
end

def update?
cart.shopper.person == current_person
end

class Scope < ApplicationScope
def resolve
scope.all
end
end
end
end
66 changes: 43 additions & 23 deletions app/furniture/marketplace/carts/_cart.html.erb
Original file line number Diff line number Diff line change
@@ -1,24 +1,44 @@
<div class="-mx-4 mt-8 overflow-hidden shadow ring-1 ring-black ring-opacity-5 sm:-mx-6 md:mx-0 md:rounded-lg">
<table class="min-w-full divide-y divide-gray-300 table-fixed">
<thead class="bg-gray-50">
<tr>
<th scope="col" class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-6">
<%= Marketplace::Product.human_attribute_name(:name) %>
</th>
<th scope="col" class="hidden px-3 py-3.5 text-left text-sm font-semibold text-gray-900 lg:table-cell">
<%= Marketplace::Product.human_attribute_name(:description) %>
</th>
<th scope="col" class="hidden px-3 py-3.5 text-left text-sm font-semibold text-gray-900 sm:table-cell">
<%= Marketplace::Product.human_attribute_name(:price) %>
</th>
<th scope="col" class="w-48">&nbsp;</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200 bg-white">
<%- cart.marketplace.products.each do |product| %>
<%= render cart.cart_products.find_or_initialize_by(product: product) %>
<%- end %>
</tbody>
<%= render "marketplace/carts/footer", cart: cart %>
</table>
<div id="<%= dom_id(cart) %>">

<%- if cart.delivery_address.blank? %>
<%= form_with model: cart.location do |cart_form| %>
<%= render "text_field", attribute: :delivery_address, form: cart_form %>

<%= cart_form.submit %>
<%- end %>
<%- else %>
<div class="flex flex-wrap">
<p class="p-3">
Delivering to <%= cart.delivery_address %>

</p>
<%= button_to "Change Address", cart.location, params: { cart: { delivery_address: nil } }%>
</div>

<%- end %>

<div class="-mx-4 mt-8 overflow-hidden shadow ring-1 ring-black ring-opacity-5 sm:-mx-6 md:mx-0 md:rounded-lg">
<table class="min-w-full divide-y divide-gray-300 table-fixed">
<thead class="bg-gray-50">
<tr>
<th scope="col" class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-6">
<%= Marketplace::Product.human_attribute_name(:name) %>
</th>
<th scope="col" class="hidden px-3 py-3.5 text-left text-sm font-semibold text-gray-900 lg:table-cell">
<%= Marketplace::Product.human_attribute_name(:description) %>
</th>
<th scope="col" class="hidden px-3 py-3.5 text-left text-sm font-semibold text-gray-900 sm:table-cell">
<%= Marketplace::Product.human_attribute_name(:price) %>
</th>
<th scope="col" class="w-48">&nbsp;</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200 bg-white">
<%- cart.marketplace.products.each do |product| %>
<%= render cart.cart_products.find_or_initialize_by(product: product) %>
<%- end %>
</tbody>
<%= render "marketplace/carts/footer", cart: cart %>
</table>
</div>
</div>
5 changes: 3 additions & 2 deletions app/furniture/marketplace/carts/_footer.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
<tr>
<td class="text-left px-3 py-3.5 text-right" colspan="8">
<%= render "marketplace/carts/total", cart: cart %>
<%= button_to("Checkout", cart.location(child: :checkout), data: { turbo: false }) %>
<%- if cart.delivery_address.present? %>
<%= button_to("Checkout", cart.location(child: :checkout), data: { turbo: false }) %>
<%- end %>
</td>

</tr>
</tfoot>
12 changes: 7 additions & 5 deletions app/furniture/marketplace/carts/_total.html.erb
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
<span id="cart-total-<%= cart.id%>" class="w-full flex flex-col">
<span class="text-right">
<span id="cart-total-<%= cart.id%>" class="w-full flex flex-col sm:text-right">
<span>
Products:
<%= humanized_money_with_symbol(cart.product_total) %></span>
<span class="text-right">Delivery:
<%= humanized_money_with_symbol(cart.delivery_fee) %></span>
<span class="text-right font-bold">
<%- if cart.delivery_address.present? %>
<span>Delivery:
<%= humanized_money_with_symbol(cart.delivery_fee) %></span>
<%- end %>
<span class="font-bold">
Total: <%= humanized_money_with_symbol(cart.price_total) %>
</span>
</span>
24 changes: 24 additions & 0 deletions app/furniture/marketplace/carts_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
class Marketplace
class CartsController < Controller
def update
authorize(cart)
cart.update(cart_params)
respond_to do |format|
format.html do
redirect_to cart.room.location
end
format.turbo_stream do
render turbo_stream: [turbo_stream.replace(dom_id(cart), cart)]
end
end
end

def cart
policy_scope(marketplace.carts).find(params[:id])
end

def cart_params
policy(Cart).permit(params.require(:cart))
end
end
end
3 changes: 0 additions & 3 deletions app/furniture/marketplace/checkout.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@ def create_stripe_session(success_url:, cancel_url:)
mode: "payment",
success_url: success_url,
cancel_url: cancel_url,
shipping_address_collection: {
allowed_countries: ["US"],
},
payment_intent_data: {
transfer_group: cart.id
}
Expand Down
8 changes: 7 additions & 1 deletion spec/furniture/marketplace/cart_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,13 @@
cart.cart_products.create!(product: product_b, quantity: 2)
end

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

context "when the #delivery_address is present" do
let(:cart) { create(:marketplace_cart, delivery_address: "123", marketplace: marketplace) }

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

describe "#product_total" do
Expand Down
21 changes: 21 additions & 0 deletions spec/furniture/marketplace/carts_controller_request_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
require "rails_helper"

RSpec.describe Marketplace::CartsController, type: :request do
let(:marketplace) { create(:marketplace) }
let(:space) { marketplace.space }
let(:room) { marketplace.room }
let(:person) { create(:person) }

let(:shopper) { create(:marketplace_shopper, person: person) }

describe "#update" do
it "changes the delivery address" do
cart = create(:marketplace_cart, marketplace: marketplace, shopper: shopper)
sign_in(space, person)

put polymorphic_path(cart.location), params: {cart: {delivery_address: "123 N West St"}}

expect(response).to redirect_to(room.location)
end
end
end

0 comments on commit 1f9dc06

Please sign in to comment.