Skip to content

Commit

Permalink
coupon code
Browse files Browse the repository at this point in the history
  • Loading branch information
michelson committed Jul 21, 2024
1 parent cdcb97f commit f7c380b
Show file tree
Hide file tree
Showing 29 changed files with 434 additions and 39 deletions.
Binary file added .DS_Store
Binary file not shown.
8 changes: 4 additions & 4 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ GIT

GIT
remote: https://github.com/hotwired/turbo-rails.git
revision: e376852bfb273f69f4ebb54cf516b99fcbaa7acb
revision: 9b17a3be3705786d72c3ae77fde5a9b3006555d7
branch: main
specs:
turbo-rails (2.0.5)
turbo-rails (2.0.6)
actionpack (>= 6.0.0)
activejob (>= 6.0.0)
railties (>= 6.0.0)
Expand Down Expand Up @@ -319,7 +319,7 @@ GEM
mini_magick (>= 4.9.5, < 5)
ruby-vips (>= 2.0.17, < 3)
io-console (0.7.2)
irb (1.13.2)
irb (1.14.0)
rdoc (>= 4.0.0)
reline (>= 0.4.2)
jbuilder (2.11.5)
Expand Down Expand Up @@ -457,7 +457,7 @@ GEM
qdrant-ruby (0.9.3)
faraday (>= 2.0.1, < 3)
racc (1.8.0)
rack (3.1.6)
rack (3.1.7)
rack-protection (3.0.6)
rack
rack-session (2.0.0)
Expand Down
Binary file added app/.DS_Store
Binary file not shown.
53 changes: 53 additions & 0 deletions app/controllers/coupons_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
class CouponsController < ApplicationController
before_action :authenticate_user!
before_action :set_coupon, only: [:show, :edit, :update, :destroy]

def index
@profile = User.find_by(username: params[:id] || params[:user_id])

@coupons = current_user.coupons
end

def show
end

def new
@coupon = current_user.coupons.new
end

def create
@coupon = current_user.coupons.new(coupon_params)

if @coupon.save
redirect_to user_coupon_path(current_user.username, @coupon), notice: 'Coupon was successfully created.'
else
render :new, status: 422
end
end

def edit
end

def update
if @coupon.update(coupon_params)
redirect_to user_coupon_path(current_user.username, @coupon), notice: 'Coupon was successfully updated.'
else
render :edit
end
end

def destroy
@coupon.destroy
redirect_to user_coupons_path(current_user.username), notice: 'Coupon was successfully destroyed.'
end

private

def set_coupon
@coupon = current_user.coupons.find(params[:id])
end

def coupon_params
params.require(:coupon).permit(:code, :discount_type, :discount_amount, :expires_at)
end
end
21 changes: 19 additions & 2 deletions app/controllers/product_checkout_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def create
product.product_shippings.pluck(:country)
end.uniq

session = Stripe::Checkout::Session.create({
checkout_params = {
payment_method_types: ['card'],
line_items: cart_items,
mode: 'payment',
Expand All @@ -45,7 +45,24 @@ def create
enabled: true
},
shipping_options: generate_shipping_options,
})
}

if params[:promo_code].present?
checkout_params.merge!({discounts: [{ coupon: params[:promo_code] }]})

@cart.product_cart_items.map(&:product).each do |product|
redirect_to( "/product_cart", notice: "Invalid promo code") and return if product.coupon&.code != params[:promo_code]
end
end

# allow_promotion_codes: @product&.coupon.exists?,

begin
session = Stripe::Checkout::Session.create(checkout_params)
rescue Stripe::InvalidRequestError => e
redirect_to "/product_cart", notice: e
return
end

@purchase.update(stripe_session_id: session.id)
redirect_to session.url, allow_other_host: true
Expand Down
28 changes: 14 additions & 14 deletions app/controllers/products_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def destroy
private

def set_product
@product = Product.friendly.find(params[:id])
@product = current_user.products.friendly.find(params[:id])
end

def authorize_user
Expand All @@ -90,19 +90,19 @@ def authorize_user

def product_params
params.require(:product).permit(
:title,
:limited_edition, :limited_edition_count, :include_digital_album, :visibility,
:name_your_price, :shipping_days, :shipping_begins_on, :shipping_within_country_price,
:shipping_worldwide_price, :quantity, :playlist_id,
:title, :description, :price, :sku, :category, :status, :stock_quantity,
:limited_edition, :limited_edition_count, :include_digital_album,
:visibility, :name_your_price, :shipping_days, :shipping_begins_on,
:shipping_within_country_price, :shipping_worldwide_price, :quantity,
:shipping_days,
images: [], product_variants_attributes: [:id, :name, :price, :stock_quantity, :_destroy],
product_options_attributes: [:id, :name, :quantity, :sku, :_destroy],
product_images_attributes: [:id, :name, :description, :image, :_destroy],
product_shippings_attributes: [:id, :country, :base_cost, :additional_cost, :_destroy]
:title, :coupon_id,
:limited_edition, :limited_edition_count, :include_digital_album, :visibility,
:name_your_price, :shipping_days, :shipping_begins_on, :shipping_within_country_price,
:shipping_worldwide_price, :quantity, :playlist_id,
:title, :description, :price, :sku, :category, :status, :stock_quantity,
:limited_edition, :limited_edition_count, :include_digital_album,
:visibility, :name_your_price, :shipping_days, :shipping_begins_on,
:shipping_within_country_price, :shipping_worldwide_price, :quantity,
:shipping_days,
images: [], product_variants_attributes: [:id, :name, :price, :stock_quantity, :_destroy],
product_options_attributes: [:id, :name, :quantity, :sku, :_destroy],
product_images_attributes: [:id, :name, :description, :image, :_destroy],
product_shippings_attributes: [:id, :country, :base_cost, :additional_cost, :_destroy]
)
end
end
2 changes: 2 additions & 0 deletions app/helpers/coupons_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
module CouponsHelper
end
51 changes: 51 additions & 0 deletions app/models/coupon.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# app/models/coupon.rb
class Coupon < ApplicationRecord
belongs_to :user
has_many :products

validates :code, presence: true, uniqueness: true
validates :discount_type, presence: true
validates :discount_amount, presence: true, numericality: { greater_than: 0 }
validates :expires_at, presence: true

enum discount_type: { percentage: 'percentage', fixed_amount: 'fixed_amount' }

scope :active, -> { where('expires_at > ?', Time.current) }

after_create :create_stripe_coupon
before_destroy :delete_stripe_coupon

def active?
expires_at > Time.current
end

private

def create_stripe_coupon
stripe_coupon = if percentage?
Stripe::Coupon.create({
percent_off: discount_amount,
duration: 'once',
id: code
})
else
Stripe::Coupon.create({
amount_off: (discount_amount * 100).to_i, # Convert to cents
currency: 'usd',
duration: 'once',
id: code
})
end

update(stripe_id: stripe_coupon.id)
rescue Stripe::StripeError => e
errors.add(:base, "Stripe error: #{e.message}")
throw :abort
end

def delete_stripe_coupon
Stripe::Coupon.delete(stripe_id) if stripe_id.present?
rescue Stripe::StripeError => e
Rails.logger.error "Failed to delete Stripe coupon: #{e.message}"
end
end
4 changes: 4 additions & 0 deletions app/models/product.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ class Product < ApplicationRecord

belongs_to :user
belongs_to :album, class_name: 'Playlist', optional: true, foreign_key: :playlist_id

belongs_to :coupon, optional: true


has_many :product_variants, dependent: :destroy
has_many :product_options, dependent: :destroy
has_many :product_images
Expand Down
1 change: 1 addition & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class User < ApplicationRecord
has_many :comments
has_one :podcaster_info
has_many :products
has_many :coupons

has_many :product_purchases

Expand Down
20 changes: 20 additions & 0 deletions app/views/coupons/_coupon.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<tr>
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-default sm:pl-0">
<%= coupon.code %>
</td>
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-default sm:pl-0">
<%= coupon.discount_type.titleize %>
</td>
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-default sm:pl-0">
<%= number_to_currency(coupon.discount_amount) %>
</td>
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-default sm:pl-0">
<%= coupon.expires_at.strftime("%B %d, %Y at %I:%M %p") %>
</td>
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-default sm:pl-0">

<%= link_to 'View', user_coupon_path(current_user.username, coupon), class: 'btn btn-sm btn-info' %>
<%= link_to 'Edit', edit_user_coupon_path(current_user.username, coupon), class: 'btn btn-sm btn-warning' %>
<%= link_to 'Delete', user_coupon_path(current_user.username, coupon), method: :delete, data: { turbo_method: :delete, turbo_confirm: 'Are you sure?' }, class: 'btn btn-sm btn-danger' %>
</td>
</tr>
18 changes: 18 additions & 0 deletions app/views/coupons/_form.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<!-- app/views/coupons/_form.html.erb -->
<%= form_with(model: coupon, url: coupon.new_record? ? user_coupons_path(current_user.username) : user_coupon_path(current_user.username, coupon), local: true, data: {turbo_frame: "_top"}) do |form| %>

<div class="field space-y-2">
<%= form.text_field :code, class: 'form-control' %>
<%= form.label :discount_type %>
<%= form.select :discount_type, Coupon.discount_types.keys.map { |type| [type.titleize, type] }, {}, class: 'form-control' %>
<%= form.number_field :discount_amount, step: 0.01, class: 'form-control' %>
<%= form.label :expires_at %>
<%= form.datetime_local_field :expires_at, class: 'form-control' %>
<%= form.submit class: 'btn btn-primary' %>
</div>

<% end %>
10 changes: 10 additions & 0 deletions app/views/coupons/edit.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<div class="space-y-2 mx-auto max-w-lg">

<h1 class="text-lg">Edit Coupon</h1>

<%= render 'form', coupon: @coupon %>
<%= link_to 'Show', user_coupon_path(current_user.username, @coupon), class: 'btn btn-info' %> |
<%= link_to 'Back to Coupons', user_coupons_path(current_user.username), class: 'btn btn-secondary' %>

</div>
56 changes: 56 additions & 0 deletions app/views/coupons/index.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@

<div class="bg-default">
<div class="mx-auto max-w-2xl px-4 py-16 sm:px-6 sm:py-24 lg:max-w-7xl lg:px-8">

<div class="flex items-center justify-between">
<h2 class="text-xl font-bold text-default">
<%= link_to user_path(current_user.username), class: "text-brand-600 flex items-center space-x-2" do %>
<%= heroicon("chevron-left") %>
<%= current_user.username %>
<% end %>
Coupons
</h2>

<div class="mt-6 mb-8">
<%= link_to 'New Coupon', new_user_coupon_path(current_user.username),
class: 'button-sm-outline' %>
</div>
</div>



<% if current_user == @profile %>
<nav class="-mb-px flex space-x-8 text-2xl items-center" aria-label="Tabs">
<%= link_to "Products", user_products_path(current_user.username), class: "tab-default" %>
<%= link_to "Coupons", user_coupons_path(current_user.username), class: "tab-active" %>
</nav>
<% end %>


<div class="mt-4">

<table class="min-w-full divide-y divide-subtle">
<thead>
<tr>
<th class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-default sm:pl-0">Code</th>
<th class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-default sm:pl-0">Discount Type</th>
<th class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-default sm:pl-0">Discount Amount</th>
<th class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-default sm:pl-0">Expires At</th>
<th class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-default sm:pl-0">Actions</th>
</tr>
</thead>

<tbody class="divide-y divide-muted">
<% @coupons.each do |coupon| %>
<%= render "coupon", coupon: coupon %>
<% end %>
</tbody>
</table>

</div>

<% if @coupons.blank? %>
<p class="p-4 text-muted">No coupons found</p>
<% end %>
</div>
</div>
10 changes: 10 additions & 0 deletions app/views/coupons/new.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

<div class="space-y-2 mx-auto max-w-lg">

<h1 class="text-lg">New Coupon</h1>

<%= render 'form', coupon: @coupon %>
<%= link_to 'Back to Coupons', user_coupons_path(current_user.username), class: 'btn btn-secondary' %>

</div>
Loading

0 comments on commit f7c380b

Please sign in to comment.