Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/merchant index coupon count invoice count #11

Open
wants to merge 43 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
286fecd
test: push to check repo updates
TDManning Nov 7, 2024
5cbf6fe
test: checking pull request from branch
TDManning Nov 7, 2024
db4fcdb
Merge pull request #1 from TDManning/feature/setup
TDManning Nov 7, 2024
b460c97
feat: add tests to starter for simplecov 100% coverage for my own sanity
TDManning Nov 7, 2024
3521f39
feat: create migrations for coupon table and invoice association
TDManning Nov 8, 2024
0631448
Add files via upload
TDManning Nov 8, 2024
42c2780
feat: add readme diagram and setup files
TDManning Nov 8, 2024
ff4994a
feat: create factorybot coupon model test and factory
TDManning Nov 8, 2024
33fed6d
feat: create invoice model test for associations with factory bot
TDManning Nov 8, 2024
fc5c7ea
feat: create request spec test for coupons and add to routes
TDManning Nov 8, 2024
3d8de66
feat: make a coupon controller, serializer
TDManning Nov 8, 2024
5e20156
refactor: refactor the Coupon model for a more unified test file
TDManning Nov 8, 2024
e16256e
feat: create data for testing
TDManning Nov 8, 2024
85b47e3
fix: minor changes for tests to pass
TDManning Nov 9, 2024
50dcd03
Merge pull request #2 from TDManning/feature/setup
TDManning Nov 9, 2024
bc3dc1b
refactor: modify code to reduce redundancy
TDManning Nov 9, 2024
c7f327b
refactor: reduce the redundancy in the coupon test files
TDManning Nov 9, 2024
90bae40
feat: add endpoint get all merchant coupons
TDManning Nov 9, 2024
34bec67
Merge pull request #3 from TDManning/feature/Merchant-Coupons_index-e…
TDManning Nov 9, 2024
fa6d8e1
feat: create endpoint for merchant coupon create
TDManning Nov 9, 2024
92010d0
Merge pull request #4 from TDManning/feature/merchant-coupon-create
TDManning Nov 10, 2024
99f9d76
feat: this code is all currently working up through the create endpoint
TDManning Nov 10, 2024
12eb428
feat: add a test to show only unique coupons can be added
TDManning Nov 10, 2024
02c9d15
feat: merchant cannot exceed 5 active coupons
TDManning Nov 10, 2024
3f90968
refactor: modified controller logic to use model method in show
TDManning Nov 10, 2024
bc3cf82
test: usage_count working as expected
TDManning Nov 10, 2024
b2f7fb3
feat: create activate and deactivate endpoints
TDManning Nov 10, 2024
023851b
Merge branch 'main' into feature/update-toactivate-deactivate
TDManning Nov 10, 2024
0742045
Merge pull request #5 from TDManning/feature/update-toactivate-deacti…
TDManning Nov 10, 2024
3f504e4
refactor: remove unused method and associated tests
TDManning Nov 10, 2024
11b9983
refactor: simplecov 100% for both model and request tests
TDManning Nov 10, 2024
8d86c77
Merge pull request #6 from TDManning/feature/merchant-coupon-index-so…
TDManning Nov 10, 2024
f80b0bf
feat: include tests for update endpoints
TDManning Nov 11, 2024
5a15891
feat: modify update to use update_with_status method and obtain full …
TDManning Nov 11, 2024
0b6ce83
Merge pull request #7 from TDManning/feature/coverage-indexSorted
TDManning Nov 11, 2024
b54bc75
feat: functionality for merchant coupon index sorted in postman
TDManning Nov 11, 2024
ae26c5e
test: refactor by_merchant and include rspec tests
TDManning Nov 11, 2024
282fb70
Merge pull request #8 from TDManning/feature/coverage-indexSorted
TDManning Nov 11, 2024
031fea1
feat: create merchant invoice endpoint
TDManning Nov 11, 2024
39e4e64
feat: refactor controller index action to move merchant invoice logic…
TDManning Nov 11, 2024
255ae9a
feat: creates any missing tests for the last endpoint
TDManning Nov 11, 2024
44e83d4
fix: indentation and spacing in test files
TDManning Nov 11, 2024
459e300
fix: merge changes
TDManning Nov 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added LittleShopDiagram.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: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,8 @@ rails db:schema:dump
This repo uses a pgdump file to seed the database. Your `db:seed` command will produce lots of output, and that's normal. If all your tests fail after running `db:seed`, you probably forgot to run `rails db:schema:dump`.

Run your server with `rails s` and you should be able to access endpoints via localhost:3000.


![Alt text](LittleShopDiagram.png)

Making edits in order to merge changes to main
54 changes: 54 additions & 0 deletions app/controllers/api/v1/merchants/coupons_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
class Api::V1::Merchants::CouponsController < ApplicationController
rescue_from ActiveRecord::RecordNotFound, with: :record_not_found

def index
active_status = params[:active]
coupons = Coupon.by_merchant(params[:merchant_id], active_status)

if coupons.present?
render json: CouponSerializer.new(coupons), status: :ok
else
record_not_found
end
end


def show
coupon = Coupon.find_by_merchant_and_id(params[:merchant_id], params[:id])
return record_not_found unless coupon

render json: CouponSerializer.new(coupon), status: :ok
end

def create
coupon = Coupon.create_for_merchant(params[:merchant_id], coupon_params)
if coupon&.persisted?
render json: CouponSerializer.new(coupon), status: :created
else
render json: ErrorSerializer.format_errors(coupon&.errors&.full_messages || ['Invalid parameters']), status: :unprocessable_entity
end
end

def update
coupon = Coupon.find_by_merchant_and_id(params[:merchant_id], params[:id])
return record_not_found unless coupon

if coupon.update_with_status(coupon_params)
render json: CouponSerializer.new(coupon), status: :ok
else
render json: ErrorSerializer.format_errors(coupon.errors.full_messages), status: :unprocessable_entity
end
end


private

def coupon_params
params.require(:coupon).permit(:name, :code, :discount_value, :discount_type, :active)
end


def record_not_found
render json: ErrorSerializer.format_errors(['Your query could not be completed']), status: :not_found
end
end
11 changes: 5 additions & 6 deletions app/controllers/api/v1/merchants/invoices_controller.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
class Api::V1::Merchants::InvoicesController < ApplicationController
def index
merchant = Merchant.find(params[:merchant_id])
if params[:status].present?
invoices = merchant.invoices_filtered_by_status(params[:status])
else
invoices = merchant.invoices
end
render json: InvoiceSerializer.new(invoices)
invoices = merchant.fetch_invoices(params[:status])

render json: InvoiceSerializer.new(invoices), status: :ok
rescue ActiveRecord::RecordNotFound
render json: ErrorSerializer.format_errors(['Merchant not found']), status: :not_found
end
end
46 changes: 46 additions & 0 deletions app/models/coupon.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
class Coupon < ApplicationRecord
belongs_to :merchant, required: true
has_many :invoices

validates :name, presence: true
validates :code, presence: true, uniqueness: true
validates :discount_value, presence: true
validates :discount_type, inclusion: { in: ["percent", "dollar"] }
validate :merchant_cannot_exceed_five_active_coupons, if: :active?

def self.by_merchant(merchant_id, active_status = nil)
coupons = where(merchant_id: merchant_id)
coupons = coupons.where(active: active_status) unless active_status.nil?
coupons
end

def self.find_by_merchant_and_id(merchant_id, coupon_id)
find_by(merchant_id: merchant_id, id: coupon_id)
end

def self.create_for_merchant(merchant_id, params)
merchant = Merchant.find_by(id: merchant_id)
return nil unless merchant
merchant.coupons.create(params)
end

def usage_count
invoices.count
end

def update_with_status(params)
update(params)
end

private

def merchant_cannot_exceed_five_active_coupons
return unless merchant.present?

if merchant.coupons.where(active: true).count >= 5
errors.add(:base, 'Merchant cannot have more than 5 active coupons')
end
end
end


1 change: 1 addition & 0 deletions app/models/invoice.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
class Invoice < ApplicationRecord
belongs_to :customer
belongs_to :merchant
belongs_to :coupon, optional: true
has_many :invoice_items, dependent: :destroy
has_many :transactions, dependent: :destroy

Expand Down
17 changes: 15 additions & 2 deletions app/models/merchant.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ class Merchant < ApplicationRecord
has_many :items, dependent: :destroy
has_many :invoices, dependent: :destroy
has_many :customers, through: :invoices
# has_many :invoice_items, through: :invoices
# has_many :transactions, through: :invoices
has_many :invoice_items, through: :invoices
has_many :transactions, through: :invoices
has_many :coupons

def self.sorted_by_creation
Merchant.order("created_at DESC")
Expand All @@ -14,6 +15,14 @@ def self.filter_by_status(status)
self.joins(:invoices).where("invoices.status = ?", status).select("distinct merchants.*")
end

def coupons_count
coupons.count
end

def invoice_coupon_count
invoices.where.not(coupon_id: nil).count
end

def item_count
items.count
end
Expand All @@ -35,6 +44,10 @@ def invoices_filtered_by_status(status)
invoices.where(status: status)
end

def fetch_invoices(status = nil)
status.present? ? invoices_filtered_by_status(status) : invoices
end

def self.find_all_by_name(name)
Merchant.where("name iLIKE ?", "%#{name}%")
end
Expand Down
14 changes: 14 additions & 0 deletions app/serializers/coupon_serializer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class CouponSerializer
include JSONAPI::Serializer

set_type :coupon
attributes :name, :code, :discount_value, :discount_type, :active, :merchant_id, :usage_count

attribute :merchant_name do |coupon|
coupon.merchant.name
end

attribute :usage_count do |coupon|
coupon.usage_count
end
end
10 changes: 5 additions & 5 deletions app/serializers/error_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ class ErrorSerializer
def self.format_errors(messages)
{
message: 'Your query could not be completed',
errors: messages
errors: Array(messages)
}
end

def self.format_invalid_search_response
{
message: "your query could not be completed",
errors: ["invalid search params"]
{
message: "your query could not be completed",
errors: ["invalid search params"]
}
end
end
end
2 changes: 1 addition & 1 deletion app/serializers/invoice_serializer.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class InvoiceSerializer
include JSONAPI::Serializer
attributes :merchant_id, :customer_id, :status
attributes :merchant_id, :customer_id, :status, :coupon_id
end
8 changes: 8 additions & 0 deletions app/serializers/merchant_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,12 @@ class MerchantSerializer
} do |merchant|
merchant.item_count
end

attribute :coupons_count do |merchant|
merchant.coupons_count
end

attribute :invoice_coupon_count do |merchant|
merchant.invoice_coupon_count
end
end
2 changes: 1 addition & 1 deletion config/environments/test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
config.cache_store = :null_store

# Render exception templates for rescuable exceptions and raise for other exceptions.
config.action_dispatch.show_exceptions = :rescuable
config.action_dispatch.show_exceptions = :none

# Disable request forgery protection in test environment.
config.action_controller.allow_forgery_protection = false
Expand Down
3 changes: 3 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@
resources :items, only: :index, controller: "merchants/items"
resources :customers, only: :index, controller: "merchants/customers"
resources :invoices, only: :index, controller: "merchants/invoices"
resources :coupons, only: [:index, :show, :create, :update], controller: "merchants/coupons"
end
end
end
end


14 changes: 14 additions & 0 deletions db/migrate/20241108002837_add_coupons_table.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class AddCouponsTable < ActiveRecord::Migration[7.1]
def change
create_table :coupons do |t|
t.string :name
t.string :code
t.float :discount_value
t.string :discount_type
t.boolean :active, default: true
t.references :merchant, null: false, foreign_key: true

t.timestamps
end
end
end
6 changes: 6 additions & 0 deletions db/migrate/20241108003953_add_coupon_to_invoices.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class AddCouponToInvoices < ActiveRecord::Migration[7.1]
def change
add_reference :invoices, :coupon, foreign_key: true, null: true
end
end

78 changes: 77 additions & 1 deletion db/schema.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading