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

fix: display products in cart #74

Merged
merged 4 commits into from
Dec 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
127 changes: 86 additions & 41 deletions lib/store/inventory.ex
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,13 @@ defmodule Store.Inventory do
|> Flop.validate_and_run(flop, for: Order)
end

def list_user_draft_order(user_id) do
Order
|> where(user_id: ^user_id)
|> where(status: :draft)
|> Repo.one()
end

defp status_filter(q, status), do: where(q, [o], o.status in ^status)

def update_status(order, attrs) do
Expand All @@ -189,6 +196,13 @@ defmodule Store.Inventory do
|> Repo.all()
end

def list_order_products(order_id) do
OrdersProducts
|> where(order_id: ^order_id)
|> preload([:product])
|> Repo.all()
end

@doc """
Gets a single order.

Expand Down Expand Up @@ -330,48 +344,70 @@ defmodule Store.Inventory do
alias Store.Accounts.User

def purchase(%User{} = user, %Product{} = product, product_params) do
order =
Order
|> where(user_id: ^user.id)
|> where(status: :draft)
|> Repo.one()
|> Repo.preload([:user, :products])
order = get_order_draft_by_id(user.id, preloads: [])

if order do
order_product =
OrdersProducts
|> where(order_id: ^order.id)
|> where(product_id: ^product.id)
|> Repo.one()

{val, _} = Integer.parse(product_params["quantity"])

if order_product != nil do
if order_product.quantity + val <= product.max_per_user do
update_order_product(order_product, %{quantity: order_product.quantity + val})
else
{:error, "The maximum quantity for this product per user is #{product.max_per_user}."}
end
case order do
%Order{} ->
handle_existing_order(order, product, product_params)

nil ->
handle_new_order(user, product, product_params)
end
end

defp handle_existing_order(order, product, product_params) do
quantity = String.to_integer(product_params["quantity"])

order_products =
OrdersProducts
|> where(order_id: ^order.id, product_id: ^product.id)
|> Repo.all()

total_quantity_user =
Enum.reduce(order_products, 0, fn order_product, acc -> acc + order_product.quantity end)

if total_quantity_user + quantity > product.max_per_user do
{:error, "The maximum quantity for this product per user is #{product.max_per_user}."}
else
size_found =
Enum.any?(order_products, fn order_product ->
order_product.size == String.to_existing_atom(product_params["size"])
end)

if size_found do
update_order_products(order_products, product_params, quantity)
else
add_product_to_order(order, product, product_params)
end
else
{:ok, order} = create_order(%{user_id: user.id})
add_product_to_order(order, product, product_params)

{:ok, product}
end
end

defp update_order_products(order_products, product_params, quantity) do
Enum.each(order_products, fn order_product ->
if order_product.size == String.to_existing_atom(product_params["size"]) do
update_order_product(order_product, %{quantity: order_product.quantity + quantity})
end
end)
end

defp handle_new_order(user, product, product_params) do
{:ok, order} = create_order(%{user_id: user.id})
add_product_to_order(order, product, product_params)
end

def add_product_to_order(%Order{} = order, %Product{} = product, product_params) do
{val, _} = Integer.parse(product_params["quantity"])
quantity = String.to_integer(product_params["quantity"])
size = product_params["size"]

if update_stock_sizes(product, size, val) == {:error, "Not enough stock."} do
if update_stock_sizes(product, size, quantity) == {:error, "Not enough stock."} do
{:error, "Not enough stock."}
else
create_order_product(%{
order_id: order.id,
product_id: product.id,
quantity: val,
quantity: quantity,
size: size
})
end
Expand All @@ -389,12 +425,22 @@ defmodule Store.Inventory do
product.sizes
|> Map.update(size_key, 0, &(&1 - quantity))

product_stock = Enum.sum(Map.values(updated_sizes))
product_stock =
updated_sizes
|> Map.values()
|> Enum.filter(&is_number(&1))
|> Enum.sum()

size_stock = Map.get(updated_sizes, size_key)

if product_stock < 0 do
if size_stock < 0 do
{:error, "Not enough stock."}
else
update_product_stock_sizes(product, updated_sizes, product_stock)
transformed_sizes =
Map.from_struct(updated_sizes)
|> Map.drop([:id])

update_product_stock_sizes(product, transformed_sizes, product_stock)
end
end

Expand Down Expand Up @@ -469,17 +515,15 @@ defmodule Store.Inventory do
|> where(status: :draft)
|> Repo.one()

order =
order
|> Repo.preload(:products)
order_products =
OrdersProducts
|> where(order_id: ^order.id)
|> preload([:product])
|> Repo.all()

if order do
Enum.reduce(order.products, 0, fn product, acc ->
acc + product.price
end)
else
0
end
Enum.reduce(order_products, 0, fn order_product, acc ->
acc + order_product.quantity * order_product.product.price
end)
end

def total_price_partnership_cart(id) do
Expand Down Expand Up @@ -545,10 +589,11 @@ defmodule Store.Inventory do
|> Flop.validate_and_run(flop, for: OrderHistory)
end

def get_order_product_by_ids(order_id, product_id) do
def get_order_product_by_ids(order_id, product_id, size) do
OrdersProducts
|> where(order_id: ^order_id)
|> where(product_id: ^product_id)
|> where(size: ^size)
|> Repo.one()
end

Expand Down
46 changes: 17 additions & 29 deletions lib/store_web/live/cart_live/index.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@ defmodule StoreWeb.CartLive.Index do
use StoreWeb, :live_view
import Store.Inventory
alias Store.Repo
alias Store.Inventory.Order
alias Store.Mailer
alias StoreWeb.Emails.OrdersEmail

@impl true
def mount(_params, _session, socket) do
{:ok, socket}
{:ok, assign(socket, :orders, list_orders(preloads: :products))}
order = list_user_draft_order(socket.assigns.current_user.id)

{:ok,
socket
|> assign(:order, order)
|> assign(:order_products, list_order_products(order.id))}
end

@impl true
Expand All @@ -37,35 +40,20 @@ defmodule StoreWeb.CartLive.Index do
|> push_redirect(to: Routes.order_index_path(socket, :index))}
end

def handle_event("delete", %{"id" => id}, socket) do
def handle_event("delete", %{"id" => id, "size" => size}, socket) do
current_user = socket.assigns.current_user

order = get_order_draft_by_id(current_user.id, preloads: :products)

quantity = Enum.count(order.products)

if quantity == 1 do
order
|> Order.changeset(%{status: :canceled})
|> Repo.update!()
else
order_product = get_order_product_by_ids(order.id, id)

Repo.delete(order_product)
end

{:noreply, socket}
end

defp get_quantity(order_id, product_id) do
order_product = get_order_product_by_ids(order_id, product_id)

order_product.quantity
end
size = String.to_existing_atom(size)
order = get_order_draft_by_id(current_user.id, preloads: [])
order_product = get_order_product_by_ids(order.id, id, size)

defp get_size(order_id, product_id) do
order_product = get_order_product_by_ids(order_id, product_id)
product = get_product!(order_product.product_id, preloads: [])
update_stock(product, size, order_product.quantity)
Repo.delete(order_product)

order_product.size
{:noreply,
socket
|> put_flash(:info, "Product removed from cart successfully.")
|> push_redirect(to: Routes.cart_index_path(socket, :index))}
end
end
Loading