From 755038391d44ef44bdcf2ef52d66aa420a0c1d6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rio=20Rodrigues?= Date: Sat, 2 Dec 2023 23:16:59 +0000 Subject: [PATCH 1/4] fix: products in cart display --- lib/store/inventory.ex | 88 ++++++++--- lib/store_web/live/cart_live/index.ex | 45 ++---- lib/store_web/live/cart_live/index.html.heex | 155 ++++++++----------- lib/store_web/live/product_live/edit.ex | 4 +- 4 files changed, 148 insertions(+), 144 deletions(-) diff --git a/lib/store/inventory.ex b/lib/store/inventory.ex index 86ab56c..76a517a 100644 --- a/lib/store/inventory.ex +++ b/lib/store/inventory.ex @@ -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 @@ -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. @@ -338,20 +352,37 @@ defmodule Store.Inventory do |> Repo.preload([:user, :products]) if order do - order_product = + order_products = 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}."} + |> Repo.all() + + quantity = String.to_integer(product_params["quantity"]) + + total_quantity_user = + Enum.reduce(order_products, 0, fn order_product, acc -> acc + order_product.quantity end) + + if order_products != nil do + if total_quantity_user + quantity > product.max_per_user, + do: + {:error, "The maximum quantity for this product per user is #{product.max_per_user}."} + + controlo = + for(order_product <- order_products) do + if order_product.size == String.to_existing_atom(product_params["size"]) do + update_order_product(order_product, %{quantity: order_product.quantity + quantity}) + 1 + else + 0 + end + end + + if Enum.sum(controlo) == 0 do + add_product_to_order(order, product, product_params) end + + {:ok, product} else add_product_to_order(order, product, product_params) end @@ -389,12 +420,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 @@ -469,17 +510,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 @@ -545,10 +584,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 diff --git a/lib/store_web/live/cart_live/index.ex b/lib/store_web/live/cart_live/index.ex index f744636..6564182 100644 --- a/lib/store_web/live/cart_live/index.ex +++ b/lib/store_web/live/cart_live/index.ex @@ -9,8 +9,12 @@ defmodule StoreWeb.CartLive.Index do @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 @@ -37,35 +41,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 diff --git a/lib/store_web/live/cart_live/index.html.heex b/lib/store_web/live/cart_live/index.html.heex index a2c5168..5597399 100644 --- a/lib/store_web/live/cart_live/index.html.heex +++ b/lib/store_web/live/cart_live/index.html.heex @@ -3,86 +3,63 @@
    - <%= for order <- @orders do %> - <%= if @current_user && @current_user.id == order.user_id do %> - <%= if order.status == :draft do %> - <%= for product <- order.products do %> -
  • -
    - Moss green canvas compact backpack with double top zipper, zipper front pouch, and matching carry handle and backpack straps. + <%= for order_product <- @order_products do %> +
  • +
    + Moss green canvas compact backpack with double top zipper, zipper front pouch, and matching carry handle and backpack straps. +
    +
    +
    +
    + -
    -
    -
    - -

    - <%= product.price %> € -

    -
    - -
    - - Quantity: <%= get_quantity(order.id, product.id) %> - - Size: <%= get_size(order.id, product.id) %> -
    -
    - -
    -
    -
    - -

    - - - In stock +

    + <%= order_product.product.price %> €

    -
  • - <% end %> - <% end %> - <% end %> +
+ +
+ + Quantity: <%= order_product.quantity %> + + Size: <%= order_product.size %> +
+ + +
+ +
+ <% end %> @@ -120,7 +97,7 @@
Sócio
- <%= if @current_user && @current_user.partnership == true do %> + <%= if @current_user && @current_user.partnership==true do %> <% else %> @@ -130,18 +107,14 @@
Total
- <%= for order <- @orders do %> - <%= if @current_user && @current_user.id == order.user_id && order.status == :draft do %> - <%= if @current_user && @current_user.partnership do %> -
- <%= total_price_partnership_cart(@current_user.id) %> € -
- <% else %> -
- <%= total_price_cart(@current_user.id) %> € -
- <% end %> - <% end %> + <%= if @current_user && @current_user.partnership do %> +
+ <%= total_price_partnership_cart(@current_user.id) %> € +
+ <% else %> +
+ <%= total_price_cart(@current_user.id) %> € +
<% end %> diff --git a/lib/store_web/live/product_live/edit.ex b/lib/store_web/live/product_live/edit.ex index b1fb62b..f732ca5 100644 --- a/lib/store_web/live/product_live/edit.ex +++ b/lib/store_web/live/product_live/edit.ex @@ -11,10 +11,12 @@ defmodule StoreWeb.ProductLive.Edit do @impl true def handle_params(%{"id" => id}, _, socket) do + product = Inventory.get_product!(id, []) + {:noreply, socket |> assign(:current_page, :products) - |> assign(:page_title, "Edit Product") + |> assign(:page_title, "#{product.name}") |> assign(:product, Inventory.get_product!(id, [])) |> assign(:current_user, socket.assigns[:current_user] || nil)} end From a250672bfcfd445d9430eb12cb6fd9d05a4f8b30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rio=20Rodrigues?= Date: Sat, 2 Dec 2023 23:22:47 +0000 Subject: [PATCH 2/4] fix: run formatter --- lib/store_web/live/cart_live/index.ex | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/store_web/live/cart_live/index.ex b/lib/store_web/live/cart_live/index.ex index 6564182..eb911ef 100644 --- a/lib/store_web/live/cart_live/index.ex +++ b/lib/store_web/live/cart_live/index.ex @@ -3,7 +3,6 @@ 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 From a9b8bf249563a2a0192d02a61cd7d392484b1168 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rio=20Rodrigues?= Date: Sat, 2 Dec 2023 23:39:09 +0000 Subject: [PATCH 3/4] chore: refactor some code --- lib/store/inventory.ex | 100 +++++++++++++++++++++++------------------ 1 file changed, 56 insertions(+), 44 deletions(-) diff --git a/lib/store/inventory.ex b/lib/store/inventory.ex index 76a517a..8ebb9fb 100644 --- a/lib/store/inventory.ex +++ b/lib/store/inventory.ex @@ -344,65 +344,77 @@ 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_user_draft_order(user) - if order do - order_products = - OrdersProducts - |> where(order_id: ^order.id) - |> where(product_id: ^product.id) - |> Repo.all() - - quantity = String.to_integer(product_params["quantity"]) - - total_quantity_user = - Enum.reduce(order_products, 0, fn order_product, acc -> acc + order_product.quantity end) - - if order_products != nil do - if total_quantity_user + quantity > product.max_per_user, - do: - {:error, "The maximum quantity for this product per user is #{product.max_per_user}."} - - controlo = - for(order_product <- order_products) do - if order_product.size == String.to_existing_atom(product_params["size"]) do - update_order_product(order_product, %{quantity: order_product.quantity + quantity}) - 1 - else - 0 - end - end - - if Enum.sum(controlo) == 0 do - add_product_to_order(order, product, product_params) - end - - {:ok, product} + case order do + %Order{} -> + handle_existing_order(order, product, product_params) + + nil -> + handle_new_order(user, product, product_params) + end + end + + defp get_user_draft_order(user) do + Order + |> where(user_id: ^user.id, status: :draft) + |> Repo.one() + |> Repo.preload([:user, :products]) + 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 From ff39e4578a517810b235c9b89feedd83a9b66773 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rio=20Rodrigues?= Date: Sat, 2 Dec 2023 23:43:03 +0000 Subject: [PATCH 4/4] fix: remove unnecessary function --- lib/store/inventory.ex | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/lib/store/inventory.ex b/lib/store/inventory.ex index 8ebb9fb..684b4f9 100644 --- a/lib/store/inventory.ex +++ b/lib/store/inventory.ex @@ -344,7 +344,7 @@ defmodule Store.Inventory do alias Store.Accounts.User def purchase(%User{} = user, %Product{} = product, product_params) do - order = get_user_draft_order(user) + order = get_order_draft_by_id(user.id, preloads: []) case order do %Order{} -> @@ -355,13 +355,6 @@ defmodule Store.Inventory do end end - defp get_user_draft_order(user) do - Order - |> where(user_id: ^user.id, status: :draft) - |> Repo.one() - |> Repo.preload([:user, :products]) - end - defp handle_existing_order(order, product, product_params) do quantity = String.to_integer(product_params["quantity"])