diff --git a/lib/store/inventory.ex b/lib/store/inventory.ex index 86ab56c..684b4f9 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. @@ -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 @@ -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 @@ -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 @@ -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 diff --git a/lib/store_web/live/cart_live/index.ex b/lib/store_web/live/cart_live/index.ex index f744636..eb911ef 100644 --- a/lib/store_web/live/cart_live/index.ex +++ b/lib/store_web/live/cart_live/index.ex @@ -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 @@ -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 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 @@
+ +
+ + 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