Current section
7 Versions
Jump to
Current section
7 Versions
Compare versions
12
files changed
+308
additions
-18
deletions
| @@ -11,12 +11,19 @@ | |
| 11 11 | <<"lib/ex_catalog/mix/tasks/install.ex">>,<<"lib/ex_catalog/util.ex">>, |
| 12 12 | <<"lib/ex_catalog/repo.ex">>,<<"lib/ex_catalog/config.ex">>, |
| 13 13 | <<"lib/ex_catalog/schema">>,<<"lib/ex_catalog/schema/category.ex">>, |
| 14 | + <<"lib/ex_catalog/schema/manufacturer">>, |
| 15 | + <<"lib/ex_catalog/schema/manufacturer/slug.ex">>, |
| 14 16 | <<"lib/ex_catalog/schema/video.ex">>, |
| 15 17 | <<"lib/ex_catalog/schema/currency.ex">>, |
| 16 18 | <<"lib/ex_catalog/schema/product.ex">>,<<"lib/ex_catalog/schema/meta.ex">>, |
| 17 | - <<"lib/ex_catalog/schema/image.ex">>,<<"lib/ex_catalog/schema/product">>, |
| 19 | + <<"lib/ex_catalog/schema/image.ex">>,<<"lib/ex_catalog/schema/video">>, |
| 20 | + <<"lib/ex_catalog/schema/video/slug.ex">>, |
| 21 | + <<"lib/ex_catalog/schema/product">>, |
| 18 22 | <<"lib/ex_catalog/schema/product/category.ex">>, |
| 23 | + <<"lib/ex_catalog/schema/product/slug.ex">>, |
| 19 24 | <<"lib/ex_catalog/schema/product/variation.ex">>, |
| 25 | + <<"lib/ex_catalog/schema/product/variation.slug.ex">>, |
| 26 | + <<"lib/ex_catalog/schema/manufacturer.ex">>, |
| 20 27 | <<"lib/ex_catalog/schema/category">>, |
| 21 28 | <<"lib/ex_catalog/schema/category/slug.ex">>, |
| 22 29 | <<"lib/ex_catalog/exceptions.ex">>,<<"lib/ex_catalog/autoslug.ex">>, |
| @@ -78,4 +85,4 @@ | |
| 78 85 | {<<"optional">>,true}, |
| 79 86 | {<<"repository">>,<<"hexpm">>}, |
| 80 87 | {<<"requirement">>,<<"~> 1.7">>}]]}. |
| 81 | - {<<"version">>,<<"1.5.3">>}. |
| 88 | + {<<"version">>,<<"1.5.4">>}. |
| @@ -6,6 +6,7 @@ defmodule ExCatalog do | |
| 6 6 | |
| 7 7 | alias ExCatalog.Category |
| 8 8 | alias ExCatalog.Product |
| 9 | + alias ExCatalog.Manufacturer |
| 9 10 | |
| 10 11 | @doc """ |
| 11 12 | List version. |
| @@ -182,15 +183,13 @@ defmodule ExCatalog do | |
| 182 183 | reply |
| 183 184 | |
| 184 185 | _ -> |
| 185 | - {p, metadata} = reply |
| 186 | - |
| 187 186 | modified = |
| 188 | - Enum.map(p, fn x -> |
| 187 | + Enum.map(reply.entries, fn x -> |
| 189 188 | {:ok, price} = ExCatalog.Currencies.convert(x.price, currency) |
| 190 189 | %{x | price: price} |
| 191 190 | end) |
| 192 191 | |
| 193 | - {modified, metadata} |
| 192 | + {modified, reply.metadata} |
| 194 193 | end |
| 195 194 | end |
| 196 195 | |
| @@ -267,12 +266,13 @@ defmodule ExCatalog do | |
| 267 266 | order = Keyword.get(opts, :order) || :desc |
| 268 267 | by = Keyword.get(opts, :order_by) || :updated_at |
| 269 268 | order_by = [{order, by}] |
| 269 | + origins = Keyword.get(opts, :origins) || [] |
| 270 270 | |
| 271 271 | query = |
| 272 272 | case(deleted) do |
| 273 273 | false -> |
| 274 | - from(ExCatalog.Product, |
| 275 | - where: [category_id: ^category.id], |
| 274 | + from(p in ExCatalog.Product, |
| 275 | + where: p.category_id == ^category.id and p.origin not in ^origins, |
| 276 276 | order_by: ^order_by, |
| 277 277 | preload: [:variations], |
| 278 278 | preload: [:categories], |
| @@ -283,8 +283,8 @@ defmodule ExCatalog do | |
| 283 283 | ) |
| 284 284 | |
| 285 285 | true -> |
| 286 | - from(ExCatalog.Product, |
| 287 | - where: [category_id: ^category.id], |
| 286 | + from(p in ExCatalog.Product, |
| 287 | + where: p.category_id == ^category.id and p.origin not in ^origins, |
| 288 288 | preload: [:variations], |
| 289 289 | preload: [:categories], |
| 290 290 | preload: [:metas], |
| @@ -329,18 +329,205 @@ defmodule ExCatalog do | |
| 329 329 | reply |
| 330 330 | |
| 331 331 | _ -> |
| 332 | - {data, meta} = reply |
| 333 | - |
| 334 332 | modified = |
| 335 | - Enum.map(data, fn x -> |
| 333 | + Enum.map(reply.entries, fn x -> |
| 336 334 | {:ok, price} = ExCatalog.Currencies.convert(x.price, currency) |
| 337 335 | %{x | price: price} |
| 338 336 | end) |
| 339 337 | |
| 340 | - {modified, meta} |
| 338 | + {modified, reply.metadata} |
| 341 339 | end |
| 342 340 | end |
| 343 341 | |
| 342 | + ### |
| 343 | + @doc """ |
| 344 | + List product with preloads by category and optional currency conversion. |
| 345 | + |
| 346 | + ## Examples |
| 347 | + |
| 348 | + iex> ExCatalog.products_by_category("test_category", "2242", :USD, false, order_by: :sku) |
| 349 | + |
| 350 | + |
| 351 | + """ |
| 352 | + def products_by_country(slug, limit \\ 25, currency \\ :USD, deleted \\ false, opts \\ []) |
| 353 | + when is_list(slug) do |
| 354 | + products_by_country(slug, limit, nil, nil, currency, deleted, opts) |
| 355 | + end |
| 356 | + |
| 357 | + def products_by_country(slug, limit, metadata, cursor, currency, deleted, opts) do |
| 358 | + import Ecto.Query |
| 359 | + import Ecto.SoftDelete.Query |
| 360 | + |
| 361 | + order = Keyword.get(opts, :order) || :desc |
| 362 | + by = Keyword.get(opts, :order_by) || :updated_at |
| 363 | + order_by = [{order, by}] |
| 364 | + |
| 365 | + query = |
| 366 | + case(deleted) do |
| 367 | + false -> |
| 368 | + from(p in ExCatalog.Product, |
| 369 | + where: p.slug not in ^slug, |
| 370 | + order_by: ^order_by, |
| 371 | + preload: [:variations], |
| 372 | + preload: [:categories], |
| 373 | + preload: [:metas], |
| 374 | + preload: [:primary_image], |
| 375 | + preload: [:images], |
| 376 | + preload: [:videos] |
| 377 | + ) |
| 378 | + |
| 379 | + true -> |
| 380 | + from(p in ExCatalog.Product, |
| 381 | + where: p.slug not in ^slug, |
| 382 | + preload: [:variations], |
| 383 | + preload: [:categories], |
| 384 | + preload: [:metas], |
| 385 | + preload: [:primary_image], |
| 386 | + preload: [:images], |
| 387 | + preload: [:videos] |
| 388 | + ) |
| 389 | + |> with_undeleted |
| 390 | + end |
| 391 | + |
| 392 | + reply = |
| 393 | + case cursor do |
| 394 | + :before -> |
| 395 | + @repo.paginate( |
| 396 | + query, |
| 397 | + before: metadata.before, |
| 398 | + include_total_count: true, |
| 399 | + cursor_fields: [:inserted_at, :id], |
| 400 | + limit: limit |
| 401 | + ) |
| 402 | + |
| 403 | + :after -> |
| 404 | + @repo.paginate( |
| 405 | + query, |
| 406 | + after: metadata.after, |
| 407 | + include_total_count: true, |
| 408 | + cursor_fields: [:inserted_at, :id], |
| 409 | + limit: limit |
| 410 | + ) |
| 411 | + |
| 412 | + _ -> |
| 413 | + @repo.paginate( |
| 414 | + query, |
| 415 | + include_total_count: true, |
| 416 | + cursor_fields: [:inserted_at, :id], |
| 417 | + limit: limit |
| 418 | + ) |
| 419 | + end |
| 420 | + |
| 421 | + case currency do |
| 422 | + nil -> |
| 423 | + reply |
| 424 | + |
| 425 | + _ -> |
| 426 | + modified = |
| 427 | + Enum.map(reply.entries, fn x -> |
| 428 | + {:ok, price} = ExCatalog.Currencies.convert(x.price, currency) |
| 429 | + %{x | price: price} |
| 430 | + end) |
| 431 | + |
| 432 | + {modified, reply.metadata} |
| 433 | + end |
| 434 | + end |
| 435 | + |
| 436 | + @doc """ |
| 437 | + List product with preloads by category and optional currency conversion. |
| 438 | + |
| 439 | + ## Examples |
| 440 | + |
| 441 | + iex> ExCatalog.products_by_category("test_category", "2242", :USD, false, order_by: :sku) |
| 442 | + |
| 443 | + |
| 444 | + """ |
| 445 | + def products_by_manufacturer(slug, limit \\ 25, currency \\ :USD, deleted \\ false, opts \\ []) do |
| 446 | + products_by_manufacturer(slug, limit, nil, nil, currency, deleted, opts) |
| 447 | + end |
| 448 | + |
| 449 | + def products_by_manufacturer(slug, limit, metadata, cursor, currency, deleted, opts) do |
| 450 | + manufacturer = @repo.get_by(%Manufacturer{}, slug: slug) |
| 451 | + |
| 452 | + import Ecto.Query |
| 453 | + import Ecto.SoftDelete.Query |
| 454 | + |
| 455 | + order = Keyword.get(opts, :order) || :desc |
| 456 | + by = Keyword.get(opts, :order_by) || :updated_at |
| 457 | + order_by = [{order, by}] |
| 458 | + |
| 459 | + query = |
| 460 | + case(deleted) do |
| 461 | + false -> |
| 462 | + from(ExCatalog.Product, |
| 463 | + where: [manufacturer: ^manufacturer], |
| 464 | + order_by: ^order_by, |
| 465 | + preload: [:variations], |
| 466 | + preload: [:categories], |
| 467 | + preload: [:metas], |
| 468 | + preload: [:primary_image], |
| 469 | + preload: [:images], |
| 470 | + preload: [:videos] |
| 471 | + ) |
| 472 | + |
| 473 | + true -> |
| 474 | + from(ExCatalog.Product, |
| 475 | + where: [origin: ^slug], |
| 476 | + preload: [:variations], |
| 477 | + preload: [:categories], |
| 478 | + preload: [:metas], |
| 479 | + preload: [:primary_image], |
| 480 | + preload: [:images], |
| 481 | + preload: [:videos] |
| 482 | + ) |
| 483 | + |> with_undeleted |
| 484 | + end |
| 485 | + |
| 486 | + reply = |
| 487 | + case cursor do |
| 488 | + :before -> |
| 489 | + @repo.paginate( |
| 490 | + query, |
| 491 | + before: metadata.before, |
| 492 | + include_total_count: true, |
| 493 | + cursor_fields: [:inserted_at, :id], |
| 494 | + limit: limit |
| 495 | + ) |
| 496 | + |
| 497 | + :after -> |
| 498 | + @repo.paginate( |
| 499 | + query, |
| 500 | + after: metadata.after, |
| 501 | + include_total_count: true, |
| 502 | + cursor_fields: [:inserted_at, :id], |
| 503 | + limit: limit |
| 504 | + ) |
| 505 | + |
| 506 | + _ -> |
| 507 | + @repo.paginate( |
| 508 | + query, |
| 509 | + include_total_count: true, |
| 510 | + cursor_fields: [:inserted_at, :id], |
| 511 | + limit: limit |
| 512 | + ) |
| 513 | + end |
| 514 | + |
| 515 | + case currency do |
| 516 | + nil -> |
| 517 | + reply |
| 518 | + |
| 519 | + _ -> |
| 520 | + modified = |
| 521 | + Enum.map(reply.entries, fn x -> |
| 522 | + {:ok, price} = ExCatalog.Currencies.convert(x.price, currency) |
| 523 | + %{x | price: price} |
| 524 | + end) |
| 525 | + |
| 526 | + {modified, reply.metadata} |
| 527 | + end |
| 528 | + end |
| 529 | + |
| 530 | + ### |
| 344 531 | @doc """ |
| 345 532 | Change the status active or disabled, this controls which products the user can see, (by default only the active products are displayed) |
| @@ -0,0 +1,46 @@ | |
| 1 | + defmodule ExCatalog.Manufacturer do |
| 2 | + use ExCatalog.Schema |
| 3 | + import Ecto.Changeset |
| 4 | + use EctoAutoslugField.Slug, from: :title, to: :slug |
| 5 | + use ExCatalog.AutoSlug |
| 6 | + |
| 7 | + alias ExCatalog.Manufacturer.TitleSlug |
| 8 | + |
| 9 | + @repo ExCatalog.Config.repo() |
| 10 | + |
| 11 | + schema "catalog_manufacturers" do |
| 12 | + field(:title, :string) |
| 13 | + field(:description, :string) |
| 14 | + |
| 15 | + field(:slug, TitleSlug.Type) |
| 16 | + end |
| 17 | + |
| 18 | + @doc false |
| 19 | + def changeset(schema, attrs) do |
| 20 | + schema |
| 21 | + |> cast(attrs, [:title, :description]) |
| 22 | + |> validate_required([:title]) |
| 23 | + end |
| 24 | + |
| 25 | + @doc false |
| 26 | + def changeset_assoc(schema, attrs) do |
| 27 | + schema |
| 28 | + |> changeset(attrs) |
| 29 | + end |
| 30 | + |
| 31 | + @doc """ |
| 32 | + Create a New Manufacturer |
| 33 | + |
| 34 | + ## Examples |
| 35 | + |
| 36 | + iex> manufacturer = %{title: "test Manufacturer", description: "test Manufacturers"} |
| 37 | + iex> ExCatalog.Manufacturers.new(manufacturer) |
| 38 | + |
| 39 | + |
| 40 | + """ |
| 41 | + def new(params \\ %{}, struct \\ %ExCatalog.Product{}) do |
| 42 | + struct |
| 43 | + |> changeset(params) |
| 44 | + |> @repo.insert() |
| 45 | + end |
| 46 | + end |
| @@ -0,0 +1,4 @@ | |
| 1 | + defmodule ExCatalog.Manufacturer.TitleSlug do |
| 2 | + @moduledoc false |
| 3 | + use EctoAutoslugField.Slug, from: :title, to: :slug |
| 4 | + end |
| @@ -2,6 +2,10 @@ defmodule ExCatalog.Product do | |
| 2 2 | use ExCatalog.Schema |
| 3 3 | import Ecto.Changeset |
| 4 4 | import Ecto.SoftDelete.Schema |
| 5 | + use EctoAutoslugField.Slug, from: :title, to: :slug |
| 6 | + use ExCatalog.AutoSlug |
| 7 | + |
| 8 | + alias ExCatalog.Product.TitleSlug |
| 5 9 | |
| 6 10 | @repo ExCatalog.Config.repo() |
| 7 11 | |
| @@ -11,10 +15,16 @@ defmodule ExCatalog.Product do | |
| 11 15 | field(:title, :string) |
| 12 16 | field(:sub_title, :string) |
| 13 17 | field(:description, :string) |
| 18 | + field(:model, :string) |
| 19 | + field(:origin, :string) |
| 14 20 | field(:owner_id, @foreign_key_type) |
| 15 21 | |
| 22 | + field(:slug, TitleSlug.Type) |
| 23 | + |
| 16 24 | belongs_to(:primary_image, ExCatalog.Image) |
| 17 25 | |
| 26 | + belongs_to(:manufacturer, ExCatalog.Manufacturer) |
| 27 | + |
| 18 28 | many_to_many(:variations, ExCatalog.Product, |
| 19 29 | join_through: ExCatalog.Product.Variation, |
| 20 30 | on_replace: :delete |
| @@ -35,7 +45,18 @@ defmodule ExCatalog.Product do | |
| 35 45 | @doc false |
| 36 46 | def changeset(schema, attrs) do |
| 37 47 | schema |
| 38 | - |> cast(attrs, [:sku, :price, :title, :sub_title, :description, :primary_image_id, :owner_id]) |
| 48 | + |> cast(attrs, [ |
| 49 | + :sku, |
| 50 | + :price, |
| 51 | + :title, |
| 52 | + :model, |
| 53 | + :sub_title, |
| 54 | + :description, |
| 55 | + :primary_image_id, |
| 56 | + :owner_id, |
| 57 | + :origin, |
| 58 | + :manufacturer |
| 59 | + ]) |
| 39 60 | |> validate_required([:sku, :price, :title, :sub_title, :description]) |
| 40 61 | end |
| 41 62 | |
| @@ -46,6 +67,7 @@ defmodule ExCatalog.Product do | |
| 46 67 | categories = attrs[:categories] || [] |
| 47 68 | metas = attrs[:metas] || [] |
| 48 69 | variations = attrs[:variations] || [] |
| 70 | + manufacturer = attrs[:manufacturer] || [] |
| 49 71 | |
| 50 72 | schema |
| 51 73 | |> changeset(attrs) |
| @@ -54,6 +76,7 @@ defmodule ExCatalog.Product do | |
| 54 76 | |> cast_assoc(:categories, categories) |
| 55 77 | |> cast_assoc(:metas, metas) |
| 56 78 | |> cast_assoc(:variations, variations) |
| 79 | + |> cast_assoc(:manufacturer, manufacturer) |
| 57 80 | end |
| 58 81 | |
| 59 82 | @doc """ |
Loading more files…