├── .gitignore
├── .rspec
├── .ruby-version
├── .tool-versions
├── Gemfile
├── Gemfile.lock
├── README.md
├── Rakefile
├── app
├── channels
│ └── application_cable
│ │ ├── channel.rb
│ │ └── connection.rb
├── controllers
│ ├── admin
│ │ └── v1
│ │ │ ├── api_controller.rb
│ │ │ ├── categories_controller.rb
│ │ │ ├── coupons_controller.rb
│ │ │ ├── dashboard
│ │ │ ├── dashboard_controller.rb
│ │ │ ├── sales_ranges_controller.rb
│ │ │ ├── summaries_controller.rb
│ │ │ └── top_five_products_controller.rb
│ │ │ ├── home_controller.rb
│ │ │ ├── licenses_controller.rb
│ │ │ ├── orders_controller.rb
│ │ │ ├── products_controller.rb
│ │ │ ├── system_requirements_controller.rb
│ │ │ └── users_controller.rb
│ ├── application_controller.rb
│ ├── concerns
│ │ ├── .keep
│ │ ├── authenticatable.rb
│ │ ├── simple_error_renderable.rb
│ │ └── static_token_authenticatable.rb
│ ├── juno
│ │ └── v1
│ │ │ └── payment_confirmations_controller.rb
│ └── storefront
│ │ └── v1
│ │ ├── api_controller.rb
│ │ ├── categories_controller.rb
│ │ ├── checkouts_controller.rb
│ │ ├── coupon_validations_controller.rb
│ │ ├── games_controller.rb
│ │ ├── home_controller.rb
│ │ ├── orders_controller.rb
│ │ ├── products_controller.rb
│ │ └── wish_items_controller.rb
├── jobs
│ ├── admin
│ │ ├── alocate_license_job.rb
│ │ └── finish_delivered_orders_job.rb
│ ├── application_job.rb
│ └── juno
│ │ └── charge_creation_job.rb
├── mailers
│ ├── application_mailer.rb
│ ├── checkout_mailer.rb
│ └── license_mailer.rb
├── models
│ ├── address.rb
│ ├── application_record.rb
│ ├── category.rb
│ ├── concerns
│ │ ├── .keep
│ │ ├── like_searchable.rb
│ │ └── paginatable.rb
│ ├── coupon.rb
│ ├── game.rb
│ ├── juno.rb
│ ├── juno
│ │ ├── charge.rb
│ │ └── credit_card_payment.rb
│ ├── license.rb
│ ├── line_item.rb
│ ├── order.rb
│ ├── product.rb
│ ├── product_category.rb
│ ├── system_requirement.rb
│ ├── user.rb
│ └── wish_item.rb
├── services
│ ├── admin
│ │ ├── alocate_licenses_service.rb
│ │ ├── dashboard
│ │ │ ├── sales_range_service.rb
│ │ │ ├── summary_service.rb
│ │ │ └── top_five_products_service.rb
│ │ ├── finish_delivered_orders_service.rb
│ │ ├── model_loading_service.rb
│ │ └── product_saving_service.rb
│ ├── juno
│ │ └── charge_creation_service.rb
│ └── storefront
│ │ ├── checkout_processor_service.rb
│ │ ├── home_loader_service.rb
│ │ └── products_filter_service.rb
├── validators
│ ├── cpf_cnpj_validator.rb
│ └── future_date_validator.rb
└── views
│ ├── admin
│ └── v1
│ │ ├── categories
│ │ ├── index.json.jbuilder
│ │ └── show.json.jbuilder
│ │ ├── coupons
│ │ ├── index.json.jbuilder
│ │ └── show.json.jbuilder
│ │ ├── dashboard
│ │ ├── sales_ranges
│ │ │ └── index.json.jbuilder
│ │ ├── summaries
│ │ │ └── index.json.jbuilder
│ │ └── top_five_products
│ │ │ └── index.json.jbuilder
│ │ ├── games
│ │ └── _game.json.jbuilder
│ │ ├── licenses
│ │ ├── index.json.jbuilder
│ │ └── show.json.jbuilder
│ │ ├── orders
│ │ ├── index.json.jbuilder
│ │ └── show.json.jbuilder
│ │ ├── products
│ │ ├── _product.json.jbuilder
│ │ ├── index.json.jbuilder
│ │ └── show.json.jbuilder
│ │ ├── system_requirements
│ │ ├── index.json.jbuilder
│ │ └── show.json.jbuilder
│ │ └── users
│ │ ├── index.json.jbuilder
│ │ └── show.json.jbuilder
│ ├── checkout_mailer
│ ├── generic_error.html.erb
│ ├── payment_error.html.erb
│ └── success.html.erb
│ ├── devise
│ └── mailer
│ │ └── reset_password_instructions.html.erb
│ ├── layouts
│ ├── mailer.html.erb
│ └── mailer.text.erb
│ ├── license_mailer
│ └── send_license.html.erb
│ ├── shared
│ ├── _pagination.json.jbuilder
│ └── _simple_error.json.jbuilder
│ └── storefront
│ └── v1
│ ├── categories
│ └── index.json.jbuilder
│ ├── checkouts
│ └── show.json.jbuilder
│ ├── coupon_validations
│ └── show.json.jbuilder
│ ├── games
│ ├── _game.json.jbuilder
│ └── index.json.jbuilder
│ ├── home
│ └── index.json.jbuilder
│ ├── orders
│ ├── index.json.jbuilder
│ └── show.json.jbuilder
│ ├── products
│ ├── _product.json.jbuilder
│ ├── index.json.jbuilder
│ └── show.json.jbuilder
│ └── wish_items
│ ├── _wish_item.json.jbuilder
│ ├── index.json.jbuilder
│ └── show.json.jbuilder
├── bin
├── bundle
├── rails
├── rake
├── setup
└── spring
├── config.ru
├── config
├── application.rb
├── boot.rb
├── cable.yml
├── credentials.yml.enc
├── credentials
│ ├── development.yml.enc
│ └── test.yml.enc
├── database.yml
├── environment.rb
├── environments
│ ├── development.rb
│ ├── production.rb
│ └── test.rb
├── initializers
│ ├── application_controller_renderer.rb
│ ├── backtrace_silencers.rb
│ ├── cors.rb
│ ├── devise.rb
│ ├── devise_token_auth.rb
│ ├── filter_parameter_logging.rb
│ ├── inflections.rb
│ ├── mime_types.rb
│ └── wrap_parameters.rb
├── locales
│ └── pt-BR
│ │ ├── active_record.yml
│ │ ├── controllers
│ │ └── coupon_validations.yml
│ │ ├── custom_validations.yml
│ │ ├── devise.yml
│ │ ├── mailers
│ │ ├── checkout_mailer.yml
│ │ └── license_mailer.yml
│ │ ├── models
│ │ └── wish_item.yml
│ │ └── services
│ │ └── checkout_processor_service.yml
├── puma.rb
├── routes.rb
├── sidekiq.yml
├── spring.rb
└── storage.yml
├── db
├── migrate
│ ├── 20200920200639_devise_token_auth_create_users.rb
│ ├── 20200927152708_create_categories.rb
│ ├── 20200927161952_create_products.rb
│ ├── 20200927162631_create_product_categories.rb
│ ├── 20200927171715_create_system_requirements.rb
│ ├── 20200927173409_create_games.rb
│ ├── 20200927192509_create_coupons.rb
│ ├── 20201018131945_create_active_storage_tables.active_storage.rb
│ ├── 20201122234724_add_status_to_products.rb
│ ├── 20210107010752_create_licenses.rb
│ ├── 20210110175644_create_wish_items.rb
│ ├── 20210114010037_add_featured_to_products.rb
│ ├── 20210207154531_create_orders.rb
│ ├── 20210209120441_create_line_items.rb
│ ├── 20210306190339_create_juno_charges.rb
│ ├── 20210306200906_create_juno_credit_card_payments.rb
│ ├── 20210314134141_add_line_item_reference_to_licenses.rb
│ └── 20210315110855_add_status_to_line_items.rb
├── schema.rb
└── seeds.rb
├── lib
├── juno_api
│ ├── auth.rb
│ ├── charge.rb
│ ├── credit_card_payment.rb
│ └── request_error.rb
├── middlewares
│ └── static_token_auth.rb
└── tasks
│ ├── .keep
│ └── dev
│ └── prime.rake
├── log
└── .keep
├── public
└── robots.txt
├── snippets
├── 1_iniciando_o_projeto.md
└── 2_configurando_autenticacao.md
├── spec
├── factories
│ ├── addresses.rb
│ ├── categories.rb
│ ├── coupons.rb
│ ├── games.rb
│ ├── juno
│ │ ├── charges.rb
│ │ └── credit_card_payments.rb
│ ├── licenses.rb
│ ├── line_items.rb
│ ├── orders.rb
│ ├── product_categories.rb
│ ├── products.rb
│ ├── system_requirements.rb
│ ├── users.rb
│ └── wish_items.rb
├── libs
│ ├── juno_api
│ │ ├── auth_spec.rb
│ │ ├── charge_spec.rb
│ │ └── credit_card_payment_spec.rb
│ └── middlewares
│ │ └── static_token_auth_spec.rb
├── models
│ ├── address_spec.rb
│ ├── category_spec.rb
│ ├── coupon_spec.rb
│ ├── game_spec.rb
│ ├── juno
│ │ ├── charge_spec.rb
│ │ └── credit_card_payment_spec.rb
│ ├── license_spec.rb
│ ├── line_item_spec.rb
│ ├── order_spec.rb
│ ├── product_category_spec.rb
│ ├── product_spec.rb
│ ├── system_requirement_spec.rb
│ ├── user_spec.rb
│ └── wish_item_spec.rb
├── rails_helper.rb
├── requests
│ ├── admin
│ │ └── v1
│ │ │ ├── categories
│ │ │ ├── admin_requests_spec.rb
│ │ │ ├── client_requests_spec.rb
│ │ │ └── unautheticated_requests_spec.rb
│ │ │ ├── coupons
│ │ │ ├── admin_requests_spec.rb
│ │ │ ├── client_requests_spec.rb
│ │ │ └── unautheticated_requests_spec.rb
│ │ │ ├── dashboard
│ │ │ ├── sales_ranges
│ │ │ │ ├── admin_requests_spec.rb
│ │ │ │ ├── client_requests_spec.rb
│ │ │ │ └── unautheticated_requests_spec.rb
│ │ │ ├── summaries
│ │ │ │ ├── admin_requests_spec.rb
│ │ │ │ ├── client_requests_spec.rb
│ │ │ │ └── unautheticated_requests_spec.rb
│ │ │ └── top_five_products
│ │ │ │ ├── admin_requests_spec.rb
│ │ │ │ ├── client_requests_spec.rb
│ │ │ │ └── unautheticated_requests_spec.rb
│ │ │ ├── home_spec.rb
│ │ │ ├── licenses
│ │ │ ├── admin_requests_spec.rb
│ │ │ ├── client_requests_spec.rb
│ │ │ └── unauthenticated_requests_spec.rb
│ │ │ ├── orders
│ │ │ ├── admin_requests_spec.rb
│ │ │ ├── client_requests_spec.rb
│ │ │ └── unautheticated_requests_spec.rb
│ │ │ ├── products
│ │ │ ├── admin_requests_spec.rb
│ │ │ ├── client_requests_spec.rb
│ │ │ └── unautheticated_requests_spec.rb
│ │ │ ├── system_requirements
│ │ │ ├── admin_requests_spec.rb
│ │ │ ├── client_requests_spec.rb
│ │ │ └── unautheticated_requests_spec.rb
│ │ │ └── users
│ │ │ ├── admin_requests_spec.rb
│ │ │ ├── client_requests_spec.rb
│ │ │ └── unautheticated_requests_spec.rb
│ ├── auth
│ │ └── v1
│ │ │ ├── sign_in_spec.rb
│ │ │ ├── sign_out_spec.rb
│ │ │ └── sign_up_spec.rb
│ ├── juno
│ │ └── v1
│ │ │ └── payment_confirmations
│ │ │ ├── authenticated_requests_spec.rb
│ │ │ └── unauthenticated_requests_spec.rb
│ └── storefront
│ │ └── v1
│ │ ├── categories
│ │ └── unathenticated_requests_spec.rb
│ │ ├── checkouts
│ │ ├── authenticated_request_spec.rb
│ │ └── unautheticated_requests_spec.rb
│ │ ├── coupon_validations
│ │ ├── authenticated_requests_spec.rb
│ │ └── unautheticated_requests_spec.rb
│ │ ├── games
│ │ ├── authenticated_requests_spec.rb
│ │ └── unautheticated_requests_spec.rb
│ │ ├── home
│ │ └── unauthenticated_requests_spec.rb
│ │ ├── orders
│ │ ├── authenticated_requests_spec.rb
│ │ └── unautheticated_requests_spec.rb
│ │ ├── products
│ │ └── unauthenticated_requests_spec.rb
│ │ └── wish_items
│ │ ├── authenticated_requests_spec.rb
│ │ └── unautheticated_requests_spec.rb
├── services
│ ├── admin
│ │ ├── alocate_licenses_service_spec.rb
│ │ ├── dashboard
│ │ │ ├── sales_range_service_spec.rb
│ │ │ ├── summary_service_spec.rb
│ │ │ └── top_five_products_service_spec.rb
│ │ ├── finish_delivered_orders_service_spec.rb
│ │ ├── model_loading_service_spec.rb
│ │ └── product_saving_service_spec.rb
│ ├── juno
│ │ └── charge_creation_service_spec.rb
│ └── storefront
│ │ ├── checkout_processor_service_spec.rb
│ │ ├── home_loader_service_spec.rb
│ │ └── products_filter_service_spec.rb
├── shared_examples
│ ├── forbidden_access_example.rb
│ ├── like_searchable_concern_example.rb
│ ├── paginatable_concern_examples.rb
│ ├── pagination_meta_attributes_examples.rb
│ ├── sign_in_examples.rb
│ └── unauthenticated_access_example.rb
├── spec_helper.rb
├── support
│ ├── factory_bot.rb
│ ├── images
│ │ └── product_image.png
│ ├── request_api.rb
│ ├── shoulda_matchers.rb
│ └── time_helpers.rb
└── validators
│ ├── cpf_cnpj_validator_spec.rb
│ └── future_date_validator_spec.rb
├── storage
└── .keep
├── tmp
├── .keep
└── pids
│ └── .keep
└── vendor
└── .keep
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files for more about ignoring files.
2 | #
3 | # If you find yourself ignoring temporary files generated by your text editor
4 | # or operating system, you probably want to add a global ignore instead:
5 | # git config --global core.excludesfile '~/.gitignore_global'
6 |
7 | # Ignore bundler config.
8 | /.bundle
9 |
10 | # Ignore all logfiles and tempfiles.
11 | /log/*
12 | /tmp/*
13 | !/log/.keep
14 | !/tmp/.keep
15 |
16 | # Ignore pidfiles, but keep the directory.
17 | /tmp/pids/*
18 | !/tmp/pids/
19 | !/tmp/pids/.keep
20 |
21 | # Ignore uploaded files in development.
22 | /storage/*
23 | !/storage/.keep
24 | .byebug_history
25 |
26 | # Ignore master key for decrypting credentials and more.
27 | /config/master.key
28 |
29 | /config/credentials/development.key
30 |
31 | /config/credentials/test.key
32 |
--------------------------------------------------------------------------------
/.rspec:
--------------------------------------------------------------------------------
1 | --require spec_helper
2 |
--------------------------------------------------------------------------------
/.ruby-version:
--------------------------------------------------------------------------------
1 | ruby-2.7.1
2 |
--------------------------------------------------------------------------------
/.tool-versions:
--------------------------------------------------------------------------------
1 | ruby 2.7.1
2 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 | git_source(:github) { |repo| "https://github.com/#{repo}.git" }
3 |
4 | ruby '2.7.1'
5 |
6 | gem 'rails', '~> 6.0.3', '>= 6.0.3.3'
7 |
8 | # Basic
9 | gem 'bootsnap', '>= 1.4.2', require: false
10 | gem 'pg', '>= 0.18', '< 2.0'
11 | gem 'puma', '~> 4.1'
12 |
13 | # Auth
14 | gem 'devise_token_auth', '~> 1.1.4'
15 |
16 | # CORS
17 | gem 'rack-cors', '~> 1.1.1'
18 |
19 | # Validation
20 | gem 'cpf_cnpj', '~> 0.5.0'
21 |
22 | # Delayed Jobs
23 | gem "sidekiq", '~> 6.1.3'
24 | gem "sidekiq-scheduler", '~> 3.0.1'
25 |
26 | # Rendering
27 | gem 'jbuilder', '~> 2.10.1'
28 |
29 | # HTTP Request
30 | gem 'httparty', '~> 0.18.1'
31 |
32 | group :development, :test do
33 | gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
34 | gem 'factory_bot_rails'
35 | gem 'faker'
36 | gem 'rspec-rails', '~> 4.0.1'
37 | gem 'shoulda-matchers', '~> 4.0'
38 | end
39 |
40 | group :development do
41 | gem 'listen', '~> 3.2'
42 | gem 'spring'
43 | gem 'spring-watcher-listen', '~> 2.0.0'
44 | end
45 |
46 | gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
47 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | # Add your own tasks in files placed in lib/tasks ending in .rake,
2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3 |
4 | require_relative 'config/application'
5 |
6 | Rails.application.load_tasks
7 |
--------------------------------------------------------------------------------
/app/channels/application_cable/channel.rb:
--------------------------------------------------------------------------------
1 | module ApplicationCable
2 | class Channel < ActionCable::Channel::Base
3 | end
4 | end
5 |
--------------------------------------------------------------------------------
/app/channels/application_cable/connection.rb:
--------------------------------------------------------------------------------
1 | module ApplicationCable
2 | class Connection < ActionCable::Connection::Base
3 | end
4 | end
5 |
--------------------------------------------------------------------------------
/app/controllers/admin/v1/api_controller.rb:
--------------------------------------------------------------------------------
1 | module Admin::V1
2 | class ApiController < ApplicationController
3 | class ForbiddenAccess < StandardError; end
4 |
5 | include Authenticatable
6 |
7 | include SimpleErrorRenderable
8 | self.simple_error_partial = "shared/simple_error"
9 |
10 | rescue_from ForbiddenAccess do
11 | render_error(message: "Forbidden access", status: :forbidden)
12 | end
13 |
14 | before_action :restrict_access_for_admin!
15 |
16 | private
17 |
18 | def restrict_access_for_admin!
19 | raise ForbiddenAccess unless current_user.admin?
20 | end
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/app/controllers/admin/v1/categories_controller.rb:
--------------------------------------------------------------------------------
1 | module Admin::V1
2 | class CategoriesController < ApiController
3 | before_action :load_category, only: [:show, :update, :destroy]
4 |
5 | def index
6 | @loading_service = Admin::ModelLoadingService.new(Category.all, searchable_params)
7 | @loading_service.call
8 | end
9 |
10 | def create
11 | @category = Category.new
12 | @category.attributes = category_params
13 | save_category!
14 | end
15 |
16 | def show; end
17 |
18 | def update
19 | @category.attributes = category_params
20 | save_category!
21 | end
22 |
23 | def destroy
24 | @category.destroy!
25 | rescue
26 | render_error(fields: @category.errors.messages)
27 | end
28 |
29 | private
30 |
31 | def load_category
32 | @category = Category.find(params[:id])
33 | end
34 |
35 | def searchable_params
36 | params.permit({ search: :name }, { order: {} }, :page, :length)
37 | end
38 |
39 | def category_params
40 | return {} unless params.has_key?(:category)
41 | params.require(:category).permit(:id, :name)
42 | end
43 |
44 | def save_category!
45 | @category.save!
46 | render :show
47 | rescue
48 | render_error(fields: @category.errors.messages)
49 | end
50 | end
51 | end
52 |
--------------------------------------------------------------------------------
/app/controllers/admin/v1/coupons_controller.rb:
--------------------------------------------------------------------------------
1 | module Admin::V1
2 | class CouponsController < ApiController
3 | before_action :load_coupon, only: [:show, :update, :destroy]
4 |
5 | def index
6 | permitted = params.permit({ search: :name }, { order: {} }, :page, :length)
7 | @loading_service = Admin::ModelLoadingService.new(Coupon.all, permitted)
8 | @loading_service.call
9 | end
10 |
11 | def create
12 | @coupon = Coupon.new
13 | @coupon.attributes = coupon_params
14 | save_coupon!
15 | end
16 |
17 |
18 | def show; end
19 |
20 | def update
21 | @coupon.attributes = coupon_params
22 | save_coupon!
23 | end
24 |
25 | def destroy
26 | @coupon.destroy!
27 | rescue
28 | render_error(fields: @coupon.errors.messages)
29 | end
30 |
31 | private
32 |
33 | def load_coupon
34 | @coupon = Coupon.find(params[:id])
35 | end
36 |
37 | def coupon_params
38 | return {} unless params.has_key?(:coupon)
39 | params.require(:coupon).permit(:id, :name, :code, :status, :discount_value, :max_use, :due_date)
40 | end
41 |
42 | def save_coupon!
43 | @coupon.save!
44 | render :show
45 | rescue
46 | render_error(fields: @coupon.errors.messages)
47 | end
48 | end
49 | end
50 |
--------------------------------------------------------------------------------
/app/controllers/admin/v1/dashboard/dashboard_controller.rb:
--------------------------------------------------------------------------------
1 | module Admin::V1::Dashboard
2 | class DashboardController < Admin::V1::ApiController
3 | def get_date(date)
4 | Time.parse(params[date], "%Y-%m-%d")
5 | rescue
6 | nil
7 | end
8 | end
9 | end
--------------------------------------------------------------------------------
/app/controllers/admin/v1/dashboard/sales_ranges_controller.rb:
--------------------------------------------------------------------------------
1 | module Admin::V1::Dashboard
2 | class SalesRangesController < DashboardController
3 | def index
4 | @service = Admin::Dashboard::SalesRangeService.new(min: get_date(:min_date), max: get_date(:max_date))
5 | @service.call
6 | end
7 | end
8 | end
--------------------------------------------------------------------------------
/app/controllers/admin/v1/dashboard/summaries_controller.rb:
--------------------------------------------------------------------------------
1 | module Admin::V1::Dashboard
2 | class SummariesController < DashboardController
3 | def index
4 | @service = Admin::Dashboard::SummaryService.new(min: get_date(:min_date), max: get_date(:max_date))
5 | @service.call
6 | end
7 | end
8 | end
--------------------------------------------------------------------------------
/app/controllers/admin/v1/dashboard/top_five_products_controller.rb:
--------------------------------------------------------------------------------
1 | module Admin::V1::Dashboard
2 | class TopFiveProductsController < DashboardController
3 | def index
4 | @service = Admin::Dashboard::TopFiveProductsService.new(min: get_date(:min_date), max: get_date(:max_date))
5 | @service.call
6 | end
7 | end
8 | end
--------------------------------------------------------------------------------
/app/controllers/admin/v1/home_controller.rb:
--------------------------------------------------------------------------------
1 | module Admin::V1
2 | class HomeController < ApiController
3 | def index
4 | render json: { message: "Uhul!" }
5 | end
6 | end
7 | end
--------------------------------------------------------------------------------
/app/controllers/admin/v1/licenses_controller.rb:
--------------------------------------------------------------------------------
1 | module Admin::V1
2 | class LicensesController < ApiController
3 | before_action :load_license, only: [:show, :update, :destroy]
4 |
5 | def index
6 | game_licenses = License.where(game_id: params[:game_id])
7 | @loading_service = Admin::ModelLoadingService.new(game_licenses, searchable_params)
8 | @loading_service.call
9 | end
10 |
11 | def create
12 | @license = License.new(game_id: params[:game_id])
13 | @license.attributes = license_params
14 | save_license!
15 | end
16 |
17 | def show; end
18 |
19 | def update
20 | @license.attributes = license_params
21 | save_license!
22 | end
23 |
24 | def destroy
25 | @license.destroy!
26 | rescue
27 | render_error(fields: @license.errors.messages)
28 | end
29 |
30 | private
31 |
32 | def load_license
33 | @license = License.find(params[:id])
34 | end
35 |
36 | def searchable_params
37 | params.permit({ search: :key }, { order: {} }, :page, :length)
38 | end
39 |
40 | def license_params
41 | return {} unless params.has_key?(:license)
42 | params.require(:license).permit(:id, :key, :platform, :status)
43 | end
44 |
45 | def save_license!
46 | @license.save!
47 | render :show
48 | rescue
49 | render_error(fields: @license.errors.messages)
50 | end
51 | end
52 | end
53 |
--------------------------------------------------------------------------------
/app/controllers/admin/v1/orders_controller.rb:
--------------------------------------------------------------------------------
1 | module Admin::V1
2 | class OrdersController < ApiController
3 | def index
4 | @loading_service = Admin::ModelLoadingService.new(Order.all, searchable_params)
5 | @loading_service.call
6 | end
7 |
8 | def show
9 | @order = Order.find(params[:id])
10 | end
11 |
12 | private
13 |
14 | def searchable_params
15 | params.permit({ order: {} }, :page, :length)
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/app/controllers/admin/v1/products_controller.rb:
--------------------------------------------------------------------------------
1 | module Admin::V1
2 | class ProductsController < ApiController
3 | before_action :load_product, only: %i(show update destroy)
4 |
5 | def index
6 | @loading_service = Admin::ModelLoadingService.new(Product.all, searchable_params)
7 | @loading_service.call
8 | end
9 |
10 | def create
11 | run_service
12 | rescue Admin::ProductSavingService::NotSavedProductError
13 | render_error(fields: @saving_service.errors)
14 | end
15 |
16 | def show; end
17 |
18 | def update
19 | run_service
20 | rescue Admin::ProductSavingService::NotSavedProductError
21 | render_error(fields: @saving_service.errors)
22 | end
23 |
24 | def destroy
25 | @product.productable.destroy!
26 | @product.destroy!
27 | rescue ActiveRecord::RecordNotDestroyed
28 | render_error(fields: @product.errors.messages.merge(@product.productable.errors.messages))
29 | end
30 |
31 | private
32 |
33 | def load_product
34 | @product = Product.find(params[:id])
35 | end
36 |
37 | def searchable_params
38 | params.permit({ search: :name }, { order: {} }, :page, :length)
39 | end
40 |
41 | def run_service
42 | @saving_service = Admin::ProductSavingService.new(product_params.to_h, @product)
43 | @saving_service.call
44 | @product = @saving_service.product
45 | render :show
46 | end
47 |
48 | def product_params
49 | return {} unless params.has_key?(:product)
50 | permitted_params = params.require(:product).permit(:id, :name, :description, :image, :price, :productable,
51 | :status, :featured, category_ids: [])
52 | permitted_params.merge(productable_params)
53 | end
54 |
55 | def productable_params
56 | productable_type = params[:product][:productable] || @product&.productable_type&.underscore
57 | return unless productable_type.present?
58 | productable_attributes = send("#{productable_type}_params")
59 | { productable_attributes: productable_attributes }
60 | end
61 |
62 | def game_params
63 | params.require(:product).permit(:mode, :release_date, :developer, :system_requirement_id)
64 | end
65 | end
66 | end
67 |
--------------------------------------------------------------------------------
/app/controllers/admin/v1/system_requirements_controller.rb:
--------------------------------------------------------------------------------
1 | module Admin::V1
2 | class SystemRequirementsController < ApiController
3 | before_action :load_system_requirement, only: [:show, :update, :destroy]
4 |
5 | def index
6 | permitted = params.permit({ search: :name }, { order: {} }, :page, :length)
7 | @loading_service = Admin::ModelLoadingService.new(SystemRequirement.all, permitted)
8 | @loading_service.call
9 | end
10 |
11 | def create
12 | @system_requirement = SystemRequirement.new
13 | @system_requirement.attributes = system_requirement_params
14 | save_system_requirement!
15 | end
16 |
17 | def show; end
18 |
19 | def update
20 | @system_requirement.attributes = system_requirement_params
21 | save_system_requirement!
22 | end
23 |
24 | def destroy
25 | @system_requirement.destroy!
26 | rescue
27 | render_error(fields: @system_requirement.errors.messages)
28 | end
29 |
30 | private
31 |
32 | def load_system_requirement
33 | @system_requirement = SystemRequirement.find(params[:id])
34 | end
35 |
36 | def system_requirement_params
37 | return {} unless params.has_key?(:system_requirement)
38 | params.require(:system_requirement).permit(:id, :name, :operational_system, :storage,
39 | :processor, :memory, :video_board)
40 | end
41 |
42 | def save_system_requirement!
43 | @system_requirement.save!
44 | render :show
45 | rescue
46 | render_error(fields: @system_requirement.errors.messages)
47 | end
48 | end
49 | end
50 |
--------------------------------------------------------------------------------
/app/controllers/admin/v1/users_controller.rb:
--------------------------------------------------------------------------------
1 | module Admin::V1
2 | class UsersController < ApiController
3 | before_action :load_user, only: [:show, :update, :destroy]
4 |
5 | def index
6 | scope_without_current_user = User.where.not(id: @current_user.id)
7 | permitted = params.permit({ search: :name }, { order: {} }, :page, :length)
8 | @loading_service = Admin::ModelLoadingService.new(scope_without_current_user, permitted)
9 | @loading_service.call
10 | end
11 |
12 | def create
13 | @user = User.new
14 | @user.attributes = user_params
15 | save_user!
16 | end
17 |
18 | def update
19 | @user.attributes = user_params
20 | save_user!
21 | end
22 |
23 | def show; end
24 |
25 | def destroy
26 | @user.destroy!
27 | rescue
28 | render_error(fields: @user.errors.messages)
29 | end
30 |
31 | private
32 |
33 | def load_user
34 | @user = User.find(params[:id])
35 | end
36 |
37 | def user_params
38 | return {} unless params.has_key?(:user)
39 | params.require(:user).permit(:id, :name, :email, :password, :password_confirmation, :profile)
40 | end
41 |
42 | def save_user!
43 | @user.save!
44 | render :show
45 | rescue
46 | render_error(fields: @user.errors.messages)
47 | end
48 | end
49 | end
50 |
--------------------------------------------------------------------------------
/app/controllers/application_controller.rb:
--------------------------------------------------------------------------------
1 | class ApplicationController < ActionController::API
2 | before_action :configure_permitted_parameters, if: :devise_controller?
3 |
4 | protected
5 |
6 | def configure_permitted_parameters
7 | devise_parameter_sanitizer.permit(:sign_up, keys: [:name, :email, :password, :password_confirmation])
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/app/controllers/concerns/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OneBitCodeBlog/e-commerce-Api-Dev/cf15a94a7f2f7ac43089ab4cdb7e7176afbc8bee/app/controllers/concerns/.keep
--------------------------------------------------------------------------------
/app/controllers/concerns/authenticatable.rb:
--------------------------------------------------------------------------------
1 | module Authenticatable
2 | extend ActiveSupport::Concern
3 |
4 | included do
5 | include DeviseTokenAuth::Concerns::SetUserByToken
6 | before_action :authenticate_user!
7 | end
8 | end
--------------------------------------------------------------------------------
/app/controllers/concerns/simple_error_renderable.rb:
--------------------------------------------------------------------------------
1 | module SimpleErrorRenderable
2 | extend ActiveSupport::Concern
3 |
4 | included do
5 | class_attribute :simple_error_partial
6 |
7 | def render_error(message: nil, fields: nil, status: :unprocessable_entity)
8 | render partial: self.class.simple_error_partial, locals: { message: message, fields: fields },
9 | status: status
10 | end
11 | end
12 | end
--------------------------------------------------------------------------------
/app/controllers/concerns/static_token_authenticatable.rb:
--------------------------------------------------------------------------------
1 | module StaticTokenAuthenticatable
2 | extend ActiveSupport::Concern
3 |
4 | included do
5 | STATIC_TOKEN_AUTH = ENV['STATIC_TOKEN_AUTH'] || Rails.application.credentials.token[:auth]
6 |
7 | before_action :authenticate!
8 |
9 | def authenticate!
10 | unless params[:token] == STATIC_TOKEN_AUTH
11 | head :unauthorized
12 | end
13 | end
14 | end
15 | end
--------------------------------------------------------------------------------
/app/controllers/juno/v1/payment_confirmations_controller.rb:
--------------------------------------------------------------------------------
1 | module Juno::V1
2 | class PaymentConfirmationsController < ApplicationController
3 | include StaticTokenAuthenticatable
4 |
5 | def create
6 | if params.has_key?(:chargeCode)
7 | Juno::Charge.find_by(code: params[:chargeCode])&.order&.update(status: :payment_accepted)
8 | end
9 | head :ok
10 | end
11 | end
12 | end
--------------------------------------------------------------------------------
/app/controllers/storefront/v1/api_controller.rb:
--------------------------------------------------------------------------------
1 | module Storefront::V1
2 | class ApiController < ApplicationController
3 | include Authenticatable
4 |
5 | include SimpleErrorRenderable
6 | self.simple_error_partial = "shared/simple_error"
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/app/controllers/storefront/v1/categories_controller.rb:
--------------------------------------------------------------------------------
1 | module Storefront::V1
2 | class CategoriesController < ApplicationController
3 |
4 | def index
5 | @categories = Category.order(:name)
6 | end
7 | end
8 | end
--------------------------------------------------------------------------------
/app/controllers/storefront/v1/checkouts_controller.rb:
--------------------------------------------------------------------------------
1 | module Storefront::V1
2 | class CheckoutsController < ApiController
3 | def create
4 | run_service
5 | rescue Storefront::CheckoutProcessorService::InvalidParamsError
6 | render_error(fields: @service.errors)
7 | end
8 |
9 | private
10 |
11 | def run_service
12 | @service = Storefront::CheckoutProcessorService.new(checkout_params)
13 | @service.call
14 | render :show
15 | end
16 |
17 | def checkout_params
18 | params.require(:checkout).permit(:payment_type, :installments, :coupon_id, :card_hash,
19 | :document, items: [:quantity, :product_id],
20 | address: [:street, :number, :city, :state, :post_code])
21 | .reverse_merge(user_id: current_user.id, installments: 1)
22 | end
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/app/controllers/storefront/v1/coupon_validations_controller.rb:
--------------------------------------------------------------------------------
1 | module Storefront::V1
2 | class CouponValidationsController < ApiController
3 | def create
4 | @coupon = Coupon.find_by(code: params[:coupon_code])
5 | @coupon.validate_use!
6 | render :show
7 | rescue Coupon::InvalidUse, NoMethodError
8 | render_error(message: I18n.t('storefront/v1/coupon_validations.create.failure'))
9 | end
10 | end
11 | end
--------------------------------------------------------------------------------
/app/controllers/storefront/v1/games_controller.rb:
--------------------------------------------------------------------------------
1 | module Storefront::V1
2 | class GamesController < ApiController
3 | def index
4 | @games = Game.includes(product: { line_items: [:order, :licenses] })
5 | .where(orders: { user_id: current_user })
6 | .select("products.*, games.*, licenses.key")
7 | end
8 | end
9 | end
--------------------------------------------------------------------------------
/app/controllers/storefront/v1/home_controller.rb:
--------------------------------------------------------------------------------
1 | module Storefront::V1
2 | class HomeController < ApplicationController
3 |
4 | def index
5 | @loader_service = Storefront::HomeLoaderService.new
6 | @loader_service.call
7 | end
8 | end
9 | end
--------------------------------------------------------------------------------
/app/controllers/storefront/v1/orders_controller.rb:
--------------------------------------------------------------------------------
1 | module Storefront::V1
2 | class OrdersController < ApiController
3 | def index
4 | @orders = current_user.orders
5 | end
6 |
7 | def show
8 | @order = current_user.orders.includes(:line_items).find(params[:id])
9 | rescue ActiveRecord::RecordNotFound
10 | render_error(message: "Forbidden access", status: :forbidden)
11 | end
12 | end
13 | end
--------------------------------------------------------------------------------
/app/controllers/storefront/v1/products_controller.rb:
--------------------------------------------------------------------------------
1 | module Storefront::V1
2 | class ProductsController < ApplicationController
3 |
4 | def index
5 | @service = Storefront::ProductsFilterService.new(search_params)
6 | @service.call
7 | end
8 |
9 | def show
10 | @product = Product.find(params[:id])
11 | end
12 |
13 | private
14 |
15 | def search_params
16 | params.permit(:search, :productable, :page, :length, order: {}, category_ids: [], price: [:min, :max],
17 | release_date: [:min, :max]).merge(productable: :game)
18 |
19 | end
20 | end
21 | end
--------------------------------------------------------------------------------
/app/controllers/storefront/v1/wish_items_controller.rb:
--------------------------------------------------------------------------------
1 | module Storefront::V1
2 | class WishItemsController < ApiController
3 |
4 | def index
5 | @wish_items = current_user.wish_items.joins(:product)
6 | .includes(:product)
7 | .order("products.name ASC")
8 | end
9 |
10 | def create
11 | @wish_item = current_user.wish_items.build(wish_item_params)
12 | @wish_item.save!
13 | render :show
14 | rescue ActiveRecord::RecordInvalid
15 | render_error(fields: @wish_item.errors.messages)
16 | end
17 |
18 | def destroy
19 | @wish_item = current_user.wish_items.find(params[:id])
20 | @wish_item.destroy!
21 | rescue ActiveRecord::RecordNotFound
22 | head :not_found
23 | end
24 |
25 | private
26 |
27 | def wish_item_params
28 | params.require(:wish_item).permit(:product_id)
29 | end
30 | end
31 | end
--------------------------------------------------------------------------------
/app/jobs/admin/alocate_license_job.rb:
--------------------------------------------------------------------------------
1 | module Admin
2 | class AlocateLicenseJob < ApplicationJob
3 | queue_as :default
4 |
5 | def perform(line_item)
6 | AlocateLicensesService.new(line_item).call
7 | end
8 | end
9 | end
--------------------------------------------------------------------------------
/app/jobs/admin/finish_delivered_orders_job.rb:
--------------------------------------------------------------------------------
1 | module Admin
2 | class FinishDeliveredOrdersJob < ApplicationJob
3 | queue_as :default
4 |
5 | def perform
6 | FinishDeliveredOrdersService.call
7 | end
8 | end
9 | end
--------------------------------------------------------------------------------
/app/jobs/application_job.rb:
--------------------------------------------------------------------------------
1 | class ApplicationJob < ActiveJob::Base
2 | # Automatically retry jobs that encountered a deadlock
3 | # retry_on ActiveRecord::Deadlocked
4 |
5 | # Most jobs are safe to ignore if the underlying records are no longer available
6 | # discard_on ActiveJob::DeserializationError
7 | end
8 |
--------------------------------------------------------------------------------
/app/jobs/juno/charge_creation_job.rb:
--------------------------------------------------------------------------------
1 | class Juno::ChargeCreationJob < ApplicationJob
2 | queue_as :default
3 |
4 | def perform(order, order_params)
5 | order.attributes = order_params.slice(:document, :card_hash)
6 | order.address = Address.new(order_params[:address])
7 | Juno::ChargeCreationService.new(order).call
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/app/mailers/application_mailer.rb:
--------------------------------------------------------------------------------
1 | class ApplicationMailer < ActionMailer::Base
2 | default from: 'from@example.com'
3 | layout 'mailer'
4 | end
5 |
--------------------------------------------------------------------------------
/app/mailers/checkout_mailer.rb:
--------------------------------------------------------------------------------
1 | class CheckoutMailer < ApplicationMailer
2 | def success
3 | mail(to: params[:order].user.email, subject: default_i18n_subject(order_number: params[:order].id))
4 | end
5 |
6 | def generic_error
7 | mail(to: params[:order].user.email, subject: default_i18n_subject(order_number: params[:order].id))
8 | end
9 |
10 | def payment_error(message)
11 | @message = message
12 | mail(to: params[:order].user.email, subject: default_i18n_subject(order_number: params[:order].id))
13 | end
14 | end
--------------------------------------------------------------------------------
/app/mailers/license_mailer.rb:
--------------------------------------------------------------------------------
1 | class LicenseMailer < ApplicationMailer
2 | def send_license
3 | mail(to: params[:license].line_item.order.user.email)
4 | end
5 | end
--------------------------------------------------------------------------------
/app/models/address.rb:
--------------------------------------------------------------------------------
1 | class Address
2 | include ActiveModel::Model
3 | include ActiveModel::Attributes
4 |
5 | attribute :street
6 | attribute :number
7 | attribute :city
8 | attribute :state
9 | attribute :post_code
10 |
11 | validates :street, presence: true
12 | validates :number, presence: true
13 | validates :city, presence: true
14 | validates :state, presence: true
15 | validates :post_code, presence: true
16 | end
--------------------------------------------------------------------------------
/app/models/application_record.rb:
--------------------------------------------------------------------------------
1 | class ApplicationRecord < ActiveRecord::Base
2 | self.abstract_class = true
3 | end
4 |
--------------------------------------------------------------------------------
/app/models/category.rb:
--------------------------------------------------------------------------------
1 | class Category < ApplicationRecord
2 | include LikeSearchable
3 | include Paginatable
4 |
5 | has_many :product_categories, dependent: :destroy
6 | has_many :products, through: :product_categories
7 |
8 | validates :name, presence: true, uniqueness: { case_sensitive: false }
9 | end
10 |
--------------------------------------------------------------------------------
/app/models/concerns/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OneBitCodeBlog/e-commerce-Api-Dev/cf15a94a7f2f7ac43089ab4cdb7e7176afbc8bee/app/models/concerns/.keep
--------------------------------------------------------------------------------
/app/models/concerns/like_searchable.rb:
--------------------------------------------------------------------------------
1 | module LikeSearchable
2 | extend ActiveSupport::Concern
3 |
4 | included do
5 | scope :like, -> (key, value) do
6 | self.where(self.arel_table[key].matches("%#{value}%"))
7 | end
8 | end
9 | end
--------------------------------------------------------------------------------
/app/models/concerns/paginatable.rb:
--------------------------------------------------------------------------------
1 | module Paginatable
2 | extend ActiveSupport::Concern
3 |
4 | MAX_PER_PAGE = 10
5 | DEFAULT_PAGE = 1
6 |
7 | included do
8 | scope :paginate, -> (page, length) do
9 | page = page.present? && page > 0 ? page : DEFAULT_PAGE
10 | length = length.present? && length > 0 ? length : MAX_PER_PAGE
11 | starts_at = (page - 1) * length
12 | limit(length).offset(starts_at)
13 | end
14 | end
15 | end
--------------------------------------------------------------------------------
/app/models/coupon.rb:
--------------------------------------------------------------------------------
1 | class Coupon < ApplicationRecord
2 | class InvalidUse < StandardError; end
3 |
4 | include LikeSearchable
5 | include Paginatable
6 |
7 | validates :name, presence: true
8 | validates :code, presence: true, uniqueness: { case_sensitive: false }
9 | validates :status, presence: true
10 | validates :discount_value, presence: true, numericality: { greater_than: 0 }
11 | validates :due_date, presence: true, future_date: true
12 |
13 | enum status: { active:1, inactive: 2 }
14 |
15 | def validate_use!
16 | raise InvalidUse unless self.active? && self.due_date >= Time.now
17 | true
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/app/models/game.rb:
--------------------------------------------------------------------------------
1 | class Game < ApplicationRecord
2 | include LikeSearchable
3 |
4 | belongs_to :system_requirement
5 | has_one :product, as: :productable
6 | has_many :licenses
7 |
8 | validates :mode, presence: true
9 | validates :release_date, presence: true
10 | validates :developer, presence: true
11 |
12 | enum mode: { pvp: 1, pve: 2, both: 3 }
13 |
14 | def ship!(line_item)
15 | Admin::AlocateLicenseJob.perform_later(line_item)
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/app/models/juno.rb:
--------------------------------------------------------------------------------
1 | module Juno
2 | def self.table_name_prefix
3 | 'juno_'
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/app/models/juno/charge.rb:
--------------------------------------------------------------------------------
1 | class Juno::Charge < ApplicationRecord
2 | belongs_to :order
3 | has_many :credit_card_payments, class_name: "Juno::CreditCardPayment"
4 |
5 | validates :key, presence: true
6 | validates :code, presence: true
7 | validates :number, presence: true,
8 | uniqueness: { scope: :order_id },
9 | numericality: { only_integer: true, greater_than: 0 }
10 | validates :amount, presence: true, numericality: { greater_than: 0 }
11 | validates :status, presence: true
12 | end
13 |
--------------------------------------------------------------------------------
/app/models/juno/credit_card_payment.rb:
--------------------------------------------------------------------------------
1 | class Juno::CreditCardPayment < ApplicationRecord
2 | belongs_to :charge
3 |
4 | validates :key, presence: true
5 | validates :release_date, presence: true
6 | validates :status, presence: true
7 | end
8 |
--------------------------------------------------------------------------------
/app/models/license.rb:
--------------------------------------------------------------------------------
1 | class License < ApplicationRecord
2 | include Paginatable
3 | include LikeSearchable
4 |
5 | belongs_to :game
6 | belongs_to :line_item, optional: true
7 |
8 | validates :key, presence: true, uniqueness: { case_sensitive: false, scope: :platform }
9 | validates :platform, presence: true
10 | validates :status, presence: true
11 | validates :line_item, presence: true, if: -> { self.status == 'in_use' }
12 |
13 | enum platform: { steam: 1, battle_net: 2, origin: 3 }
14 | enum status: { available: 1, in_use: 2, inactive: 3 }
15 | end
16 |
--------------------------------------------------------------------------------
/app/models/line_item.rb:
--------------------------------------------------------------------------------
1 | class LineItem < ApplicationRecord
2 | belongs_to :order
3 | belongs_to :product
4 | has_many :licenses
5 |
6 | validates :quantity, presence: true, numericality: { only_integer: true, greater_than: 0 }
7 | validates :payed_price, presence: true, numericality: { greater_than: 0 }
8 | validates :status, presence: true, on: :update
9 |
10 | enum status: { waiting_order: 1, preparing: 2, en_route: 3, delivered: 4 }
11 |
12 | before_validation :set_default_status, on: :create
13 |
14 | def total
15 | self.payed_price * self.quantity
16 | end
17 |
18 | def ship!
19 | self.product.productable.ship!(self)
20 | self.update!(status: :preparing)
21 | end
22 |
23 | private
24 |
25 | def set_default_status
26 | self.status = :waiting_order
27 | end
28 | end
--------------------------------------------------------------------------------
/app/models/order.rb:
--------------------------------------------------------------------------------
1 | class Order < ApplicationRecord
2 | include Paginatable
3 |
4 | DAYS_TO_DUE = 7
5 |
6 | attribute :address
7 | attribute :card_hash
8 | attribute :document
9 |
10 | belongs_to :user
11 | belongs_to :coupon, optional: true
12 | has_many :line_items
13 | has_many :juno_charges, class_name: 'Juno::Charge'
14 |
15 | validates :status, presence: true, on: :update
16 | validates :subtotal, presence: true, numericality: { greater_than: 0 }
17 | validates :total_amount, presence: true, numericality: { greater_than: 0 }
18 | validates :payment_type, presence: true
19 | validates :installments, presence: true, numericality: { only_integer: true, greater_than: 0 }
20 | validates :document, presence: true, cpf_cnpj: true, on: :create
21 |
22 | with_options if: ->{ credit_card? }, on: :create do
23 | validates :card_hash, presence: true
24 | validates :address, presence: true
25 | validates_associated :address
26 | end
27 |
28 | enum status: { processing_order: 1, processing_error: 2, waiting_payment: 3,
29 | payment_accepted: 4, payment_denied: 5, finished: 6 }
30 |
31 | enum payment_type: { credit_card: 1, billet: 2 }
32 |
33 | before_validation :set_default_status, on: :create
34 | after_commit :enqueue_juno_charge_creation, on: :create
35 | around_update :ship_order, if: -> { self.status_changed?(to: 'payment_accepted') }
36 |
37 |
38 | def due_date
39 | self.created_at + DAYS_TO_DUE.days
40 | end
41 |
42 | private
43 |
44 | def set_default_status
45 | self.status = :processing_order
46 | end
47 |
48 | def enqueue_juno_charge_creation
49 | order_attrs = { document: self.document, card_hash: self.card_hash, address: self.address.attributes }
50 | Juno::ChargeCreationJob.perform_later(self, order_attrs)
51 | end
52 |
53 | def ship_order
54 | yield
55 | self.line_items.each { |line_item| line_item.ship! }
56 | end
57 | end
58 |
--------------------------------------------------------------------------------
/app/models/product.rb:
--------------------------------------------------------------------------------
1 | class Product < ApplicationRecord
2 | include LikeSearchable
3 | include Paginatable
4 |
5 | belongs_to :productable, polymorphic: true
6 | has_many :product_categories, dependent: :destroy
7 | has_many :categories, through: :product_categories
8 | has_many :wish_items
9 | has_many :line_items
10 |
11 | has_one_attached :image
12 |
13 | validates :name, presence: true, uniqueness: { case_sensitive: false }
14 | validates :description, presence: true
15 | validates :price, presence: true, numericality: { greater_than: 0 }
16 | validates :image, presence: true
17 | validates :status, presence: true
18 | validates :featured, presence: true, if: -> { featured.nil? }
19 |
20 | enum status: { available: 1, unavailable: 2 }
21 |
22 | def sells_count
23 | LineItem.joins(:order).where(orders: { status: :finished }, product: self).sum(:quantity)
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/app/models/product_category.rb:
--------------------------------------------------------------------------------
1 | class ProductCategory < ApplicationRecord
2 | belongs_to :product
3 | belongs_to :category
4 | end
5 |
--------------------------------------------------------------------------------
/app/models/system_requirement.rb:
--------------------------------------------------------------------------------
1 | class SystemRequirement < ApplicationRecord
2 | include LikeSearchable
3 | include Paginatable
4 |
5 | has_many :games, dependent: :restrict_with_error
6 |
7 | validates :name, presence: true, uniqueness: { case_sensitive: false }
8 | validates :operational_system, presence: true
9 | validates :storage, presence: true
10 | validates :processor, presence: true
11 | validates :memory, presence: true
12 | validates :video_board, presence: true
13 | end
14 |
--------------------------------------------------------------------------------
/app/models/user.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class User < ActiveRecord::Base
4 | include LikeSearchable
5 | include Paginatable
6 |
7 | devise :database_authenticatable, :registerable,
8 | :recoverable, :rememberable, :validatable
9 |
10 | include DeviseTokenAuth::Concerns::User
11 |
12 | has_many :wish_items
13 | has_many :orders
14 |
15 | validates :name, presence: true
16 | validates :profile, presence: true
17 |
18 | enum profile: { admin: 0, client: 1 }
19 | end
20 |
--------------------------------------------------------------------------------
/app/models/wish_item.rb:
--------------------------------------------------------------------------------
1 | class WishItem < ApplicationRecord
2 | belongs_to :user
3 | belongs_to :product
4 |
5 | validates :product_id, uniqueness: { scope: :user_id }
6 | end
7 |
--------------------------------------------------------------------------------
/app/services/admin/alocate_licenses_service.rb:
--------------------------------------------------------------------------------
1 | module Admin
2 | class AlocateLicensesService
3 | def initialize(line_item)
4 | @line_item = line_item
5 | end
6 |
7 | def call
8 | licenses = @line_item.product.productable.licenses.where(status: :available).take(@line_item.quantity)
9 | License.transaction { update_licenses(licenses) }
10 | send_licenses
11 | @line_item.update!(status: :delivered)
12 | end
13 |
14 | private
15 |
16 | def update_licenses(licenses)
17 | licenses.map { |license| license.attributes = { status: :in_use, line_item: @line_item } }
18 | licenses.each { |license| license.save! }
19 | end
20 |
21 | def send_licenses
22 | @line_item.licenses.each do |license|
23 | LicenseMailer.with(license: license).send_license.deliver_later
24 | end
25 | end
26 | end
27 | end
--------------------------------------------------------------------------------
/app/services/admin/dashboard/sales_range_service.rb:
--------------------------------------------------------------------------------
1 | module Admin::Dashboard
2 | class SalesRangeService
3 | attr_reader :records
4 |
5 | def initialize(min: nil, max: nil)
6 | @min_date = min.present? ? min.beginning_of_day : nil
7 | @max_date = max.present? ? max.end_of_day : nil
8 | @records = {}
9 | end
10 |
11 | def call
12 | if @max_date.present? && @min_date.present? && @max_date - @min_date < 1.month
13 | @records = group_sales_by_day
14 | else
15 | @records = group_sales_by_month
16 | end
17 | end
18 |
19 | private
20 |
21 | def group_sales_by_day
22 | order_filter
23 | .group("year, month, day")
24 | .order("year, month, day")
25 | .pluck(order_arel[:year], order_arel[:month], order_arel[:day], line_item_arel[:total_sold])
26 | .map { |record| { date: format_date(*record[0..2]), total_sold: record[3].to_f } }
27 | end
28 |
29 | def group_sales_by_month
30 | order_filter
31 | .group("year, month")
32 | .order("year, month")
33 | .pluck(order_arel[:year], order_arel[:month], line_item_arel[:total_sold])
34 | .map { |record| { date: format_date(*record[0..1]), total_sold: record[2].to_f } }
35 | end
36 |
37 | def order_filter
38 | Order.joins(:line_items)
39 | .where(status: :finished, created_at: @min_date..@max_date)
40 | end
41 |
42 | def format_date(year, month, day = nil)
43 | year = "%04d" % year
44 | month = ("-" + "%02d" % month)
45 | day = ("-" + "%02d" % day) if day.present?
46 | year + month + day.to_s
47 | end
48 |
49 | def line_item_arel
50 | @line_item_arel if @line_item_arel.present?
51 | arel = LineItem.arel_table
52 | total_sold = (arel[:payed_price] * arel[:quantity]).sum.as('total_sold')
53 | @line_item_arel = { total_sold: total_sold }
54 | end
55 |
56 | def order_arel
57 | @order_arel if @order_arel.present?
58 | field = Order.arel_table[:created_at]
59 | @order_arel = { month: field.extract('month').as('month'), year: field.extract('year').as('year'),
60 | day: field.extract('day').as('day') }
61 | end
62 | end
63 | end
--------------------------------------------------------------------------------
/app/services/admin/dashboard/summary_service.rb:
--------------------------------------------------------------------------------
1 | module Admin::Dashboard
2 | class SummaryService
3 | attr_reader :records
4 |
5 | def initialize(min: nil, max: nil)
6 | @min_date = min.present? ? min.beginning_of_day : nil
7 | @max_date = max.present? ? max.end_of_day : nil
8 | @records = {}
9 | end
10 |
11 | def call
12 | @records[:users] = User.where(created_at: @min_date..@max_date).count
13 | @records[:products] = Product.where(created_at: @min_date..@max_date).count
14 | calculate_orders
15 | end
16 |
17 | private
18 |
19 | def calculate_orders
20 | arel = Order.arel_table
21 | calc = Order.where(status: :finished, created_at: @min_date..@max_date)
22 | .pluck(arel[:id].count, arel[:total_amount].sum).flatten
23 | @records[:orders] = calc.first
24 | @records[:profit] = calc.second
25 | end
26 | end
27 | end
--------------------------------------------------------------------------------
/app/services/admin/dashboard/top_five_products_service.rb:
--------------------------------------------------------------------------------
1 | module Admin::Dashboard
2 | class TopFiveProductsService
3 | NUMBER_OF_RECORDS = 5
4 |
5 | attr_reader :records
6 |
7 | def initialize(min: nil, max: nil)
8 | @min_date = min.present? ? min.beginning_of_day : nil
9 | @max_date = max.present? ? max.end_of_day : nil
10 | @records = []
11 | end
12 |
13 | def call
14 | @records = search_top_five.map do |product|
15 | build_product_hash(product)
16 | end
17 | @records
18 | end
19 |
20 | private
21 |
22 | def search_top_five
23 | range_date_orders = Order.where(status: :finished, created_at: @min_date..@max_date)
24 | Product.joins(line_items: :order).merge(range_date_orders).group(:id)
25 | .order('total_sold DESC, total_qty DESC')
26 | .limit(NUMBER_OF_RECORDS)
27 | .select(:id, :name, line_item_arel[:sold].as('total_sold'), line_item_arel[:quantity].as('total_qty'))
28 | end
29 |
30 | def build_product_hash(product)
31 | {
32 | product: product.name,
33 | image: Rails.application.routes.url_helpers.rails_blob_url(product.image),
34 | total_sold: product.total_sold,
35 | quantity: product.total_qty
36 | }
37 | end
38 |
39 | def line_item_arel
40 | return @line_item_arel if @line_item_arel
41 | arel = LineItem.arel_table
42 | total_sold = (arel[:payed_price] * arel[:quantity]).sum
43 | quantity_sum = arel[:quantity].sum
44 | @line_item_arel = { sold: total_sold, quantity: quantity_sum }
45 | end
46 | end
47 | end
48 |
--------------------------------------------------------------------------------
/app/services/admin/finish_delivered_orders_service.rb:
--------------------------------------------------------------------------------
1 | module Admin
2 | class FinishDeliveredOrdersService
3 | def self.call
4 | delivered_orders = Order.includes(:line_items).where(status: :payment_accepted).select do |order|
5 | order.line_items.all?(&:delivered?)
6 | end
7 | Order.where(id: delivered_orders.map(&:id)).update_all(status: :finished)
8 | end
9 | end
10 | end
--------------------------------------------------------------------------------
/app/services/admin/model_loading_service.rb:
--------------------------------------------------------------------------------
1 | module Admin
2 | class ModelLoadingService
3 | attr_reader :records, :pagination
4 |
5 | def initialize(searchable_model, params = {})
6 | @searchable_model = searchable_model
7 | @params = params || {}
8 | @records = []
9 | @pagination = {}
10 | end
11 |
12 | def call
13 | set_pagination_values
14 | searched = search_records(@searchable_model)
15 | @records = searched.order(@params[:order].to_h)
16 | .paginate(@params[:page], @params[:length])
17 | set_pagination_attributes(searched.count)
18 | end
19 |
20 | private
21 |
22 | def set_pagination_values
23 | @params[:page] = @params[:page].to_i
24 | @params[:length] = @params[:length].to_i
25 | @params[:page] = @searchable_model.model::DEFAULT_PAGE if @params[:page] <= 0
26 | @params[:length] = @searchable_model.model::MAX_PER_PAGE if @params[:length] <= 0
27 | end
28 |
29 | def search_records(searched)
30 | return searched unless @params.has_key?(:search)
31 | @params[:search].each do |key, value|
32 | searched = searched.like(key, value)
33 | end
34 | searched
35 | end
36 |
37 | def set_pagination_attributes(total_filtered)
38 | total_pages = (total_filtered / @params[:length].to_f).ceil
39 | @pagination.merge!(page: @params[:page], length: @records.count,
40 | total: total_filtered, total_pages: total_pages)
41 | end
42 | end
43 | end
--------------------------------------------------------------------------------
/app/services/admin/product_saving_service.rb:
--------------------------------------------------------------------------------
1 | module Admin
2 | class ProductSavingService
3 | class NotSavedProductError < StandardError; end
4 |
5 | attr_reader :product, :errors
6 |
7 | def initialize(params, product = nil)
8 | params = params.deep_symbolize_keys
9 | @product_params = params.reject { |key| key == :productable_attributes }
10 | @productable_params = params[:productable_attributes] || {}
11 | @errors = {}
12 | @product = product || Product.new
13 | end
14 |
15 | def call
16 | Product.transaction do
17 | @product.attributes = @product_params.reject { |key| key == :productable }
18 | build_productable
19 | ensure
20 | save!
21 | end
22 | end
23 |
24 | def build_productable
25 | @product.productable ||= @product_params[:productable].camelcase.safe_constantize.new
26 | @product.productable.attributes = @productable_params
27 | end
28 |
29 | def save!
30 | save_record!(@product.productable) if @product.productable.present?
31 | save_record!(@product)
32 | raise NotSavedProductError if @errors.present?
33 | rescue => e
34 | raise NotSavedProductError
35 | end
36 |
37 | def save_record!(record)
38 | record.save!
39 | rescue ActiveRecord::RecordInvalid
40 | @errors.merge!(record.errors.messages)
41 | end
42 | end
43 | end
--------------------------------------------------------------------------------
/app/services/juno/charge_creation_service.rb:
--------------------------------------------------------------------------------
1 | require_relative "../../../lib/juno_api/charge"
2 | require_relative "../../../lib/juno_api/credit_card_payment"
3 |
4 | module Juno
5 | class ChargeCreationService
6 | PAYMENT_ERROR_CODES = %W[289999 509999]
7 |
8 | def initialize(order)
9 | @order = order
10 | end
11 |
12 | def call
13 | create_charges
14 | create_credit_card_payment if @order.credit_card?
15 | CheckoutMailer.with(order: @order).success.deliver_later
16 | rescue JunoApi::RequestError => e
17 | set_order_error(e.error)
18 | end
19 |
20 | private
21 |
22 | def create_charges
23 | charges = JunoApi::Charge.new.create!(@order)
24 | Juno::Charge.transaction do
25 | charges.each.with_index { |charge, index| create_charge(charge, index + 1) }
26 | end
27 | @order.update!(status: :waiting_payment)
28 | end
29 |
30 | def create_credit_card_payment
31 | credit_card_payments = JunoApi::CreditCardPayment.new.create!(@order)
32 | Juno::CreditCardPayment.transaction do
33 | credit_card_payments.each { |payment| create_charge_payment(payment) }
34 | end
35 | @order.update!(status: :payment_accepted)
36 | end
37 |
38 | def set_order_error(error)
39 | if error.present? && PAYMENT_ERROR_CODES.include?(error.first['error_code'])
40 | set_payment_denied_error(error.first['message'])
41 | else
42 | set_generic_error
43 | end
44 | end
45 |
46 | def create_charge(charge, position)
47 | charge.merge!(number: position)
48 | charge[:billet_url] = charge.delete(:installment_link)
49 | charge[:key] = charge.delete(:id)
50 | @order.juno_charges.create!(charge)
51 | end
52 |
53 | def create_charge_payment(payment)
54 | charge = Juno::Charge.find_by(key: payment[:charge])
55 | payment.merge!(charge: charge)
56 | Juno::CreditCardPayment.create!(payment)
57 | end
58 |
59 | def set_payment_denied_error(message)
60 | @order.update!(status: :payment_denied)
61 | CheckoutMailer.with(order: @order).payment_error(message).deliver_later
62 | end
63 |
64 | def set_generic_error
65 | @order.update!(status: :processing_error)
66 | CheckoutMailer.with(order: @order).generic_error.deliver_later
67 | end
68 | end
69 | end
--------------------------------------------------------------------------------
/app/services/storefront/checkout_processor_service.rb:
--------------------------------------------------------------------------------
1 | module Storefront
2 | class CheckoutProcessorService
3 | class InvalidParamsError < StandardError; end
4 |
5 | attr_reader :errors, :order
6 |
7 | def initialize(params)
8 | @params = params
9 | @order = nil
10 | @errors = {}
11 | end
12 |
13 | def call
14 | check_presence_of_items_param
15 | check_emptyness_of_items_param
16 | validate_coupon
17 | do_checkout
18 | raise InvalidParamsError if @errors.present?
19 | end
20 |
21 | private
22 |
23 | def check_presence_of_items_param
24 | unless @params.has_key?(:items)
25 | @errors[:items] = I18n.t('storefront/checkout_processor_service.errors.items.presence')
26 | end
27 | end
28 |
29 | def check_emptyness_of_items_param
30 | if @params[:items].blank?
31 | @errors[:items] = I18n.t('storefront/checkout_processor_service.errors.items.empty')
32 | end
33 | end
34 |
35 | def validate_coupon
36 | return unless @params.has_key?(:coupon_id)
37 | @coupon = Coupon.find(@params[:coupon_id])
38 | @coupon.validate_use!
39 | rescue Coupon::InvalidUse, ActiveRecord::RecordNotFound
40 | @errors[:coupon] = I18n.t('storefront/checkout_processor_service.errors.coupon.invalid')
41 | end
42 |
43 | def do_checkout
44 | create_order
45 | rescue ActiveRecord::RecordInvalid => e
46 | @errors.merge! e.record.errors.messages
47 | @errors.merge!(address: e.record.address.errors.messages) if e.record.errors.has_key?(:address)
48 | end
49 |
50 | def create_order
51 | Order.transaction do
52 | @order = instantiate_order
53 | line_items = @params[:items].map { |line_item_params| instantiate_line_items(line_item_params) }
54 | save!(line_items)
55 | end
56 | rescue ArgumentError => e
57 | @errors[:base] = e.message
58 | end
59 |
60 | def instantiate_order
61 | order_params = @params.slice(:document, :payment_type, :installments, :card_hash, :coupon_id, :user_id)
62 | order = Order.new(order_params)
63 | order.address = Address.new(@params[:address])
64 | order
65 | end
66 |
67 | def instantiate_line_items(line_item_params)
68 | line_item = @order.line_items.build(line_item_params)
69 | line_item.payed_price = line_item.product.price if line_item.product.present?
70 | line_item.validate!
71 | line_item
72 | end
73 |
74 | def save!(line_items)
75 | @order.subtotal = line_items.sum(&:total).floor(2)
76 | @order.total_amount = (@order.subtotal * (1 - @coupon.discount_value / 100)).floor(2) if @coupon.present?
77 | @order.total_amount ||= @order.subtotal
78 | @order.save!
79 | line_items.each(&:save!)
80 | end
81 | end
82 | end
--------------------------------------------------------------------------------
/app/services/storefront/home_loader_service.rb:
--------------------------------------------------------------------------------
1 | module Storefront
2 | class HomeLoaderService
3 | QUANTITY_OF_RECORDS_PER_GROUP = 4
4 | MIN_RELEASE_DAYS = 7
5 |
6 | attr_reader :featured, :last_releases, :cheapest
7 |
8 | def initialize
9 | @featured = []
10 | @recently_releases = []
11 | @cheapest = []
12 | end
13 |
14 | def call
15 | games = Product.joins("JOIN games ON productable_type = 'Game' AND productable_id = games.id")
16 | .includes(productable: [:game]).where(status: :available)
17 | @featured = load_featured_games(games)
18 | @last_releases = load_last_released_games(games)
19 | @cheapest = load_cheapest_games(games)
20 | end
21 |
22 | private
23 |
24 | def load_featured_games(games)
25 | games.where(featured: true).sample(QUANTITY_OF_RECORDS_PER_GROUP)
26 | end
27 |
28 | def load_last_released_games(games)
29 | games.where(games: { release_date: MIN_RELEASE_DAYS.days.ago.beginning_of_day..Time.now.end_of_day })
30 | .sample(QUANTITY_OF_RECORDS_PER_GROUP)
31 | end
32 |
33 | def load_cheapest_games(games)
34 | games.order(price: :asc).take(QUANTITY_OF_RECORDS_PER_GROUP)
35 | end
36 | end
37 | end
--------------------------------------------------------------------------------
/app/services/storefront/products_filter_service.rb:
--------------------------------------------------------------------------------
1 | module Storefront
2 | class ProductsFilterService
3 | attr_reader :records, :pagination
4 |
5 | def initialize(params = {})
6 | @records = Product.all
7 | @params = params || {}
8 | @pagination = {}
9 | end
10 |
11 | def call
12 | set_pagination_values
13 | get_available_products
14 | searched = filter_records.select("products.*, games.mode, games.developer, games.release_date").distinct
15 | @records = searched.order(@params[:order].to_h).paginate(@params[:page], @params[:length])
16 | set_pagination_attributes(searched.size)
17 | end
18 |
19 | private
20 |
21 | def set_pagination_values
22 | @params[:page] = @params[:page].to_i
23 | @params[:length] = @params[:length].to_i
24 | @params[:page] = Product::DEFAULT_PAGE if @params[:page] <= 0
25 | @params[:length] = Product::MAX_PER_PAGE if @params[:length] <= 0
26 | end
27 |
28 | def get_available_products
29 | @records = @records.joins("JOIN games ON productable_type = 'Game' AND productable_id = games.id")
30 | .left_joins(:categories)
31 | .includes(productable: [:game], categories: {})
32 | .where(status: :available)
33 | end
34 |
35 | def filter_records
36 | searched = @records.merge filter_by_search
37 | searched.merge! filter_by_categories
38 | searched.merge! filter_by_price
39 | searched.merge! filter_by_release_date
40 | end
41 |
42 | def filter_by_search
43 | return @records.all unless @params.has_key?(:search)
44 | filtered_records = @records.like(:name, @params[:search])
45 | filtered_records = filtered_records.or(@records.like(:description, @params[:search]))
46 | filtered_records.or @records.merge(Game.like(:developer, @params[:search]))
47 | end
48 |
49 | def filter_by_categories
50 | return @records.all unless @params.has_key?(:category_ids)
51 | @records.where(categories: { id: @params[:category_ids] })
52 | end
53 |
54 | def filter_by_price
55 | min_price = @params.dig(:price, :min)
56 | max_price = @params.dig(:price, :max)
57 | return @records.all if min_price.blank? && max_price.blank?
58 | @records.where(price: min_price..max_price)
59 | end
60 |
61 | def filter_by_release_date
62 | min_date = Time.parse(@params.dig(:release_date, :min)).beginning_of_day rescue nil
63 | max_date = Time.parse(@params.dig(:release_date, :max)).end_of_day rescue nil
64 | return @records.all if min_date.blank? && max_date.blank?
65 | Game.where(release_date: min_date..max_date)
66 | end
67 |
68 | def set_pagination_attributes(total_filtered)
69 | total_pages = (total_filtered / @params[:length].to_f).ceil
70 | @pagination.merge!(page: @params[:page], length: @records.size,
71 | total: total_filtered, total_pages: total_pages)
72 | end
73 | end
74 | end
--------------------------------------------------------------------------------
/app/validators/cpf_cnpj_validator.rb:
--------------------------------------------------------------------------------
1 | require "cpf_cnpj"
2 |
3 | class CpfCnpjValidator < ActiveModel::EachValidator
4 | def validate_each(record, attribute, value)
5 | return unless value.present?
6 | unless CPF.valid?(value) || CNPJ.valid?(value)
7 | record.errors.add(attribute, :invalid_cpf_cnpj)
8 | end
9 | end
10 | end
--------------------------------------------------------------------------------
/app/validators/future_date_validator.rb:
--------------------------------------------------------------------------------
1 | class FutureDateValidator < ActiveModel::EachValidator
2 | def validate_each(record, attribute, value)
3 | if value.present? && value <= Time.zone.now
4 | message = options[:message] || :future_date
5 | record.errors.add(attribute, message)
6 | end
7 | end
8 | end
--------------------------------------------------------------------------------
/app/views/admin/v1/categories/index.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.categories do
2 | json.array! @loading_service.records, :id, :name
3 | end
4 |
5 | json.meta do
6 | json.partial! 'shared/pagination', pagination: @loading_service.pagination
7 | end
--------------------------------------------------------------------------------
/app/views/admin/v1/categories/show.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.category do
2 | json.(@category, :id, :name)
3 | end
--------------------------------------------------------------------------------
/app/views/admin/v1/coupons/index.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.coupons do
2 | json.array! @loading_service.records, :id, :name, :code, :status, :discount_value, :due_date
3 | end
4 |
5 | json.meta do
6 | json.partial! 'shared/pagination', pagination: @loading_service.pagination
7 | end
--------------------------------------------------------------------------------
/app/views/admin/v1/coupons/show.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.coupon do
2 | json.(@coupon, :id, :name, :code, :status, :discount_value, :due_date)
3 | end
--------------------------------------------------------------------------------
/app/views/admin/v1/dashboard/sales_ranges/index.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.sales_ranges @service.records
--------------------------------------------------------------------------------
/app/views/admin/v1/dashboard/summaries/index.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.summary do
2 | json.users @service.records[:users]
3 | json.products @service.records[:products]
4 | json.orders @service.records[:orders]
5 | json.profit @service.records[:profit]
6 | end
--------------------------------------------------------------------------------
/app/views/admin/v1/dashboard/top_five_products/index.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.top_five_products do
2 | json.array! @service.records do |record|
3 | json.product record[:product]
4 | json.image record[:image]
5 | json.quantity record[:quantity]
6 | json.total_sold record[:total_sold].to_f
7 | end
8 | end
--------------------------------------------------------------------------------
/app/views/admin/v1/games/_game.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.(game, :mode, :release_date, :developer)
2 | json.system_requirement game.system_requirement
--------------------------------------------------------------------------------
/app/views/admin/v1/licenses/index.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.licenses do
2 | json.array! @loading_service.records, :id, :key, :platform, :status, :game_id
3 | end
4 |
5 | json.meta do
6 | json.partial! 'shared/pagination', pagination: @loading_service.pagination
7 | end
--------------------------------------------------------------------------------
/app/views/admin/v1/licenses/show.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.license do
2 | json.(@license, :id, :key, :platform, :status, :game_id)
3 | end
--------------------------------------------------------------------------------
/app/views/admin/v1/orders/index.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.orders do
2 | json.array! @loading_service.records do |order|
3 | json.(order, :id, :status, :total_amount, :payment_type)
4 | end
5 | end
6 |
7 | json.meta do
8 | json.partial! 'shared/pagination', pagination: @loading_service.pagination
9 | end
--------------------------------------------------------------------------------
/app/views/admin/v1/orders/show.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.order do
2 | json.(@order, :id, :status, :total_amount, :subtotal, :payment_type)
3 | json.discount @order.coupon&.discount_value&.to_f
4 | json.line_items @order.line_items do |line_item|
5 | json.(line_item, :quantity, :payed_price)
6 | json.image_url rails_blob_url(line_item.product.image)
7 | json.product line_item.product.name
8 | end
9 | end
--------------------------------------------------------------------------------
/app/views/admin/v1/products/_product.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.(product, :id, :name, :description, :price, :status, :featured)
2 | json.image_url rails_blob_url(product.image)
3 | json.productable product.productable_type.underscore
4 | json.productable_id product.productable_id
5 | json.categories product.categories
--------------------------------------------------------------------------------
/app/views/admin/v1/products/index.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.products do
2 | json.array! @loading_service.records do |product|
3 | json.partial! product
4 | json.partial! product.productable
5 | end
6 | end
7 |
8 | json.meta do
9 | json.partial! 'shared/pagination', pagination: @loading_service.pagination
10 | end
--------------------------------------------------------------------------------
/app/views/admin/v1/products/show.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.product do
2 | json.partial! @product
3 | json.partial! @product.productable
4 | end
--------------------------------------------------------------------------------
/app/views/admin/v1/system_requirements/index.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.system_requirements do
2 | json.array! @loading_service.records,
3 | :id, :name, :operational_system, :storage, :processor, :memory, :video_board
4 | end
5 |
6 | json.meta do
7 | json.partial! 'shared/pagination', pagination: @loading_service.pagination
8 | end
--------------------------------------------------------------------------------
/app/views/admin/v1/system_requirements/show.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.system_requirement do
2 | json.(@system_requirement, :id, :name, :operational_system, :storage, :processor, :memory, :video_board)
3 | end
--------------------------------------------------------------------------------
/app/views/admin/v1/users/index.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.users do
2 | json.array! @loading_service.records, :id, :name, :email, :profile
3 | end
4 |
5 | json.meta do
6 | json.partial! 'shared/pagination', pagination: @loading_service.pagination
7 | end
--------------------------------------------------------------------------------
/app/views/admin/v1/users/show.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.user do
2 | json.(@user, :id, :name, :email, :profile)
3 | end
--------------------------------------------------------------------------------
/app/views/checkout_mailer/generic_error.html.erb:
--------------------------------------------------------------------------------
1 |
<%= t('.title', order_number: params[:order].id) %>
2 |
3 | <%= t('.body.html') %>
--------------------------------------------------------------------------------
/app/views/checkout_mailer/payment_error.html.erb:
--------------------------------------------------------------------------------
1 | <%= t('.title', order_number: params[:order].id) %>
2 |
3 | <%= t('.body.html', message: @message) %>
--------------------------------------------------------------------------------
/app/views/checkout_mailer/success.html.erb:
--------------------------------------------------------------------------------
1 | <%= t('.title', order_number: params[:order].id) %>
2 |
3 | <%= t('.body') %>
4 |
5 | <% if params[:order].billet? %>
6 | <%= t('.billet_payment.html', billet_link: params[:order].juno_charges.first.billet_url) %>
7 | <% elsif params[:order].credit_card? %>
8 | <%= t('.credit_card_payment') %>
9 | <% end %>
--------------------------------------------------------------------------------
/app/views/devise/mailer/reset_password_instructions.html.erb:
--------------------------------------------------------------------------------
1 | Hello <%= @resource.email %>!
2 |
3 | Someone has requested a link to change your password. You can do this through the link below.
4 |
5 | <%= link_to 'Change my password', "#{message['redirect-url']}?reset_password_token=#{@token}" %>
6 |
7 | If you didn't request this, please ignore this email.
8 | Your password won't change until you access the link above and create a new one.
9 |
--------------------------------------------------------------------------------
/app/views/layouts/mailer.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
10 |
11 | <%= yield %>
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/views/layouts/mailer.text.erb:
--------------------------------------------------------------------------------
1 | <%= yield %>
2 |
--------------------------------------------------------------------------------
/app/views/license_mailer/send_license.html.erb:
--------------------------------------------------------------------------------
1 | <%= t('.title') %>
2 |
3 | <%= t('.body', game_name: params[:license].game.product.name) %>
4 |
5 | <%= params[:license].key %>
--------------------------------------------------------------------------------
/app/views/shared/_pagination.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.page pagination[:page]
2 | json.length pagination[:length]
3 | json.total pagination[:total]
4 | json.total_pages pagination[:total_pages]
--------------------------------------------------------------------------------
/app/views/shared/_simple_error.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.errors do
2 | json.fields fields if defined?(fields) && fields.present?
3 | json.message message if defined?(message) && message.present?
4 | end
--------------------------------------------------------------------------------
/app/views/storefront/v1/categories/index.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.categories do
2 | json.array! @categories, :id, :name
3 | end
--------------------------------------------------------------------------------
/app/views/storefront/v1/checkouts/show.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.order do
2 | json.(@service.order, :id, :payment_type, :installments)
3 | json.subtotal @service.order.subtotal.to_f
4 | json.total_amount @service.order.total_amount.to_f
5 | end
--------------------------------------------------------------------------------
/app/views/storefront/v1/coupon_validations/show.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.coupon do
2 | json.(@coupon, :id, :code, :discount_value)
3 | end
--------------------------------------------------------------------------------
/app/views/storefront/v1/games/_game.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.(game, :mode, :release_date, :developer)
2 | json.system_requirement game.system_requirement
--------------------------------------------------------------------------------
/app/views/storefront/v1/games/index.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.games do
2 | json.array! @games do |game|
3 | json.(game.product, :id, :name, :description)
4 | json.image_url rails_blob_url(game.product.image)
5 | json.partial! game
6 | json.licenses game.product.line_items.map(&:licenses).flatten.map(&:key)
7 | end
8 | end
--------------------------------------------------------------------------------
/app/views/storefront/v1/home/index.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.featured do
2 | json.array! @loader_service.featured do |product|
3 | json.(product, :id, :name, :description)
4 | json.price product.price.to_f
5 | json.image_url rails_blob_url(product.image)
6 | end
7 | end
8 |
9 | json.last_releases do
10 | json.array! @loader_service.last_releases do |product|
11 | json.(product, :id, :name, :description)
12 | json.price product.price.to_f
13 | json.image_url rails_blob_url(product.image)
14 | end
15 | end
16 |
17 | json.cheapest do
18 | json.array! @loader_service.cheapest do |product|
19 | json.(product, :id, :name, :description)
20 | json.price product.price.to_f
21 | json.image_url rails_blob_url(product.image)
22 | end
23 | end
--------------------------------------------------------------------------------
/app/views/storefront/v1/orders/index.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.orders do
2 | json.array! @orders do |order|
3 | json.(order, :id, :status, :total_amount, :payment_type)
4 | end
5 | end
--------------------------------------------------------------------------------
/app/views/storefront/v1/orders/show.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.order do
2 | json.(@order, :id, :status, :total_amount, :subtotal, :payment_type)
3 | json.discount @order.coupon&.discount_value&.to_f
4 | json.line_items @order.line_items do |line_item|
5 | json.(line_item, :quantity, :payed_price)
6 | json.product line_item.product.name
7 | end
8 | end
--------------------------------------------------------------------------------
/app/views/storefront/v1/products/_product.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.(product, :id, :name, :description, :status, :featured)
2 | json.price product.price.to_f
3 | json.image_url rails_blob_url(product.image)
4 | json.productable product.productable_type.underscore
5 | json.productable_id product.productable_id
6 | json.categories product.categories
7 | json.favorited_count product.wish_items.count
8 | json.sells_count product.sells_count
--------------------------------------------------------------------------------
/app/views/storefront/v1/products/index.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.products do
2 | json.array! @service.records do |product|
3 | json.(product, :id, :name, :description)
4 | json.price product.price.to_f
5 | json.image_url rails_blob_url(product.image)
6 | json.categories product.categories.pluck(:name)
7 | end
8 | end
9 |
10 | json.meta do
11 | json.partial! 'shared/pagination', pagination: @service.pagination
12 | end
--------------------------------------------------------------------------------
/app/views/storefront/v1/products/show.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.product do
2 | json.partial! @product
3 | json.partial! @product.productable
4 | end
--------------------------------------------------------------------------------
/app/views/storefront/v1/wish_items/_wish_item.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.id wish_item.id
2 | json.(wish_item.product, :name, :description)
3 | json.price wish_item.product.price.to_f
4 | json.image_url rails_blob_url(wish_item.product.image)
5 | json.categories wish_item.product.categories.pluck(:name)
--------------------------------------------------------------------------------
/app/views/storefront/v1/wish_items/index.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.wish_items do
2 | json.array! @wish_items do |wish_item|
3 | json.partial! wish_item
4 | end
5 | end
--------------------------------------------------------------------------------
/app/views/storefront/v1/wish_items/show.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.wish_item do
2 | json.partial! @wish_item
3 | end
--------------------------------------------------------------------------------
/bin/rails:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | begin
3 | load File.expand_path('../spring', __FILE__)
4 | rescue LoadError => e
5 | raise unless e.message.include?('spring')
6 | end
7 | APP_PATH = File.expand_path('../config/application', __dir__)
8 | require_relative '../config/boot'
9 | require 'rails/commands'
10 |
--------------------------------------------------------------------------------
/bin/rake:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | begin
3 | load File.expand_path('../spring', __FILE__)
4 | rescue LoadError => e
5 | raise unless e.message.include?('spring')
6 | end
7 | require_relative '../config/boot'
8 | require 'rake'
9 | Rake.application.run
10 |
--------------------------------------------------------------------------------
/bin/setup:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require 'fileutils'
3 |
4 | # path to your application root.
5 | APP_ROOT = File.expand_path('..', __dir__)
6 |
7 | def system!(*args)
8 | system(*args) || abort("\n== Command #{args} failed ==")
9 | end
10 |
11 | FileUtils.chdir APP_ROOT do
12 | # This script is a way to setup or update your development environment automatically.
13 | # This script is idempotent, so that you can run it at anytime and get an expectable outcome.
14 | # Add necessary setup steps to this file.
15 |
16 | puts '== Installing dependencies =='
17 | system! 'gem install bundler --conservative'
18 | system('bundle check') || system!('bundle install')
19 |
20 | # puts "\n== Copying sample files =="
21 | # unless File.exist?('config/database.yml')
22 | # FileUtils.cp 'config/database.yml.sample', 'config/database.yml'
23 | # end
24 |
25 | puts "\n== Preparing database =="
26 | system! 'bin/rails db:prepare'
27 |
28 | puts "\n== Removing old logs and tempfiles =="
29 | system! 'bin/rails log:clear tmp:clear'
30 |
31 | puts "\n== Restarting application server =="
32 | system! 'bin/rails restart'
33 | end
34 |
--------------------------------------------------------------------------------
/bin/spring:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | # This file loads Spring without using Bundler, in order to be fast.
4 | # It gets overwritten when you run the `spring binstub` command.
5 |
6 | unless defined?(Spring)
7 | require 'rubygems'
8 | require 'bundler'
9 |
10 | lockfile = Bundler::LockfileParser.new(Bundler.default_lockfile.read)
11 | spring = lockfile.specs.detect { |spec| spec.name == 'spring' }
12 | if spring
13 | Gem.use_paths Gem.dir, Bundler.bundle_path.to_s, *Gem.path
14 | gem 'spring', spring.version
15 | require 'spring/binstub'
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/config.ru:
--------------------------------------------------------------------------------
1 | # This file is used by Rack-based servers to start the application.
2 |
3 | require_relative 'config/environment'
4 |
5 | run Rails.application
6 |
--------------------------------------------------------------------------------
/config/application.rb:
--------------------------------------------------------------------------------
1 | require_relative 'boot'
2 |
3 | require "rails"
4 | # Pick the frameworks you want:
5 | require "active_model/railtie"
6 | require "active_job/railtie"
7 | require "active_record/railtie"
8 | require "active_storage/engine"
9 | require "action_controller/railtie"
10 | require "action_mailer/railtie"
11 | require "action_mailbox/engine"
12 | require "action_text/engine"
13 | require "action_view/railtie"
14 | require "action_cable/engine"
15 | # require "sprockets/railtie"
16 | # require "rails/test_unit/railtie"
17 |
18 | # Require the gems listed in Gemfile, including any gems
19 | # you've limited to :test, :development, or :production.
20 | Bundler.require(*Rails.groups)
21 |
22 | module EcommerceApi
23 | class Application < Rails::Application
24 | # Initialize configuration defaults for originally generated Rails version.
25 | config.load_defaults 6.0
26 |
27 | # I18n config
28 | config.i18n.load_path += Dir[Rails.root.join('config/locales/**/*.{rb,yml}')]
29 | config.i18n.default_locale = :'pt-BR'
30 |
31 | # Settings in config/environments/* take precedence over those specified here.
32 | # Application configuration can go into files in config/initializers
33 | # -- all .rb files in that directory are automatically loaded after loading
34 | # the framework and any gems in your application.
35 |
36 | # Only loads a smaller set of middleware suitable for API only apps.
37 | # Middleware like session, flash, cookies can be added back manually.
38 | # Skip views, helpers and assets when generating a new resource.
39 | config.api_only = true
40 |
41 | config.autoload_paths += %W["#{config.root}/app/validators/"]
42 |
43 | config.active_job.queue_adapter = :sidekiq
44 | end
45 | end
46 |
--------------------------------------------------------------------------------
/config/boot.rb:
--------------------------------------------------------------------------------
1 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
2 |
3 | require 'bundler/setup' # Set up gems listed in the Gemfile.
4 | require 'bootsnap/setup' # Speed up boot time by caching expensive operations.
5 |
--------------------------------------------------------------------------------
/config/cable.yml:
--------------------------------------------------------------------------------
1 | development:
2 | adapter: async
3 |
4 | test:
5 | adapter: test
6 |
7 | production:
8 | adapter: redis
9 | url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
10 | channel_prefix: ecommerce_api_production
11 |
--------------------------------------------------------------------------------
/config/credentials.yml.enc:
--------------------------------------------------------------------------------
1 | WzAGMBoPUlSjTQ32Jc7G/lcIwkXg+9W3Fm04AhSDXcU1L63Js6rbVow5NsUsb9YQiukrpfoEjFZCZ+xvjDbu0/LhfYdmmOwczwf8uKOmbO8XNXZSToPbId2bpmqAGltlNQJ4d72+MqYoOM5Luk0q8AtWQPdWK9UQhON0UlFaioRMbH2382vmiYSlaZkcwA0gD+I6yrz20P2No3NzwAUpsv4ckXw+0aqu7ypFlS0JefPJJay1olitPbAuCdyeFETENZ31mi8Fb49nq6AwOXXTkbAW9/yvv8HTR5agDL0xg5eiHrU7cLD3UX7KT6eouwW9YNRZeNfQ9xU/gS/lqUeiV+1aClcZWMYVQ0X3PKfiKcsLxvSmAw22aZBZl50Kd27WcZsLDRPI4ZV4GspR+uSOdkahfomDk3U2doi2--6FHNx05E7+NRSSPw--RJjo63YgM5Gz+OhacCmKPQ==
--------------------------------------------------------------------------------
/config/credentials/development.yml.enc:
--------------------------------------------------------------------------------
1 | b1R8FuKKBWi1Kd3jkP1OLAzBwHLvn+5IeCqav9As+gOneB4pthgiHh/ce192GjKX1dODWUmN0bYcZor/H0+hRaCf9cKqEZbgOVrw667OFyYYh5jZRorOCY1sv9c9lptdyTDH0+wz/iiCzaS+8abbPJsCjHEm9uo8h4gzkvjkHdN+AATXfd8oAm6M6XMAaVLd5w4S49lSrhAxTIHj4ou0kIOJtigrNCdGhEB3l7XKyb1O32B8STJZM2T/Rm2Hsgs820Z9o49HOTvgy0cgcRwrFnkPRVMU9tw77tAGQtUS8Z7lh4R6u5TPy6X7Ihii4e994tdUatS3tO2QcFAoHZrr1X7CgFJ2FGlFooDh+rwLqMYeeUSfn78kvHJ4HrgN2QYxVv/Aj3zxq+AsrdmpWbE5wZBlHV7+3OYXrrPTeNO04cGz7LMn588O1qDoHPE9mK4nXIdCHX5+1658Iph3sAXkmtk2MA1crzySFSw9GaaaTRJ+w0UUjXD8lI7WLC1Gng0QkFGiy5DRA36CLuRGOnlVmduoFAso+3k/uZPkkroQaaAeUuH8U1WVWRtkx1WqAKQFzuSdlHid+WIJmZLsqX/32HD1jjW8S9d6GZKM2dR3UVRkyn3wxZFfP54zitMGhKOW371E6IXrXDx+e+lb/8SW5itb78B41UIOHBG/96Rmu7/hfdUdBxD2n9NOgef3vQGaTYhWeb+s5H/BkH4JGkYw1JPBVlamz7CkIH7YygZI/3RHs0rEGxIEwyAc+Xt0/zsEh6uiEiPrex9lOIqaNcpYJmVozjyWJlFZj0g2--jgAOxzc7bexKitw+--s1SYYKxjOkeuZyLPSfIKiw==
--------------------------------------------------------------------------------
/config/credentials/test.yml.enc:
--------------------------------------------------------------------------------
1 | gZdzZ50vkGxBm14AIwFsouRKEMT9NjVmk9tK2I/LCOdEwR2RFJEhVdlq89ps54DgB/IZgSCGDxiCF8CQyfRx8LwWK2h8q3qH2JZ1uPCSK23INcsphjkwUpFsvScAuET6Ij2apt/ZBqUCtLSiUMKSBFHl15loMbyN0XB8XSRyfftMpgqfa2/VmjIYM8YGV0ioEG/wlxNX+xBJDZ9tsJwbrjpobhl3EZYhN4RIOsxX6EiAc+BCixeSTt9iSuAawymaYtmtbGBX00K0BhLkHPy1gwNhFvJd2d/qT0zb9xVb1As9uChAZeogI61pRbGNbqTBzCK7ikC0KsNjQTUUdklF5DruiJBmB4FkSHAhkqKA+7FsA9a118P9VXrUO6sXr1vpc8ZMSxSDWArx87g5c0cjXqDuOrbhPDY7FRoAVT+EIgs6SNWwFkCwOQ6iSlORRrXBrkR3NK7o/lcKd2PMzkuX2hbrSCB8pXL1Jj2eGZWf28wWP9mm3oV9dkXa1B4vk7x+VnymAqtgRx7O49nXPkTW1z2egHTKOq5gSjOl8rdLPgTAazx0uCpkYwT7cHsU0X++M3Ysiqd8LQwkVhNhS0CTq/Jun3Xh+BTUFF5GUihH2A74A53YGf/XKO1UhMfQMHAwewIxrgGnkJ7iUPzom3+O2ygciZ01TGDYGmfHH3F9K5vMKcA8RfYoOj2gRXfovO3RgY4WmlmXn372NpJjvBO+DCb7fL6Dxrz1k04Kg28SQu6N3mawV/XFb294woawrcswMJhPA78XV2/pGXuzracsd1WT2hwA7cxyOwyB--lwUWtaJkbKlS8q83--udp1VZ3lHFp0SAUs7PRhVg==
--------------------------------------------------------------------------------
/config/database.yml:
--------------------------------------------------------------------------------
1 | default: &default
2 | adapter: postgresql
3 | encoding: unicode
4 | user: postgres
5 | password: postgres
6 | pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
7 |
8 | development:
9 | <<: *default
10 | database: ecommerce_api_development
11 |
12 | test:
13 | <<: *default
14 | database: ecommerce_api_test
15 |
16 | production:
17 | <<: *default
18 | database: ecommerce_api_production
19 | username: ecommerce_api
20 | password: <%= ENV['ECOMMERCE_API_DATABASE_PASSWORD'] %>
21 |
--------------------------------------------------------------------------------
/config/environment.rb:
--------------------------------------------------------------------------------
1 | # Load the Rails application.
2 | require_relative 'application'
3 |
4 | # Initialize the Rails application.
5 | Rails.application.initialize!
6 |
--------------------------------------------------------------------------------
/config/environments/development.rb:
--------------------------------------------------------------------------------
1 | Rails.application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb.
3 |
4 | # Configure hosts
5 | config.hosts << /[\w|\d]*\.ngrok.io/
6 |
7 | # In the development environment your application's code is reloaded on
8 | # every request. This slows down response time but is perfect for development
9 | # since you don't have to restart the web server when you make code changes.
10 | config.cache_classes = false
11 |
12 | # Do not eager load code on boot.
13 | config.eager_load = false
14 |
15 | # Show full error reports.
16 | config.consider_all_requests_local = true
17 |
18 | # Enable/disable caching. By default caching is disabled.
19 | # Run rails dev:cache to toggle caching.
20 | if Rails.root.join('tmp', 'caching-dev.txt').exist?
21 | config.cache_store = :memory_store
22 | config.public_file_server.headers = {
23 | 'Cache-Control' => "public, max-age=#{2.days.to_i}"
24 | }
25 | else
26 | config.action_controller.perform_caching = false
27 |
28 | config.cache_store = :null_store
29 | end
30 |
31 | # Store uploaded files on the local file system (see config/storage.yml for options).
32 | config.active_storage.service = :local
33 |
34 | # Don't care if the mailer can't send.
35 | config.action_mailer.raise_delivery_errors = false
36 |
37 | config.action_mailer.perform_caching = false
38 |
39 | config.action_mailer.default_url_options = { host: "http://localhost:3000" }
40 | Rails.application.routes.default_url_options[:host] = "http://localhost:3000"
41 |
42 | config.action_mailer.delivery_method = :smtp
43 | config.action_mailer.smtp_settings = {
44 | address: 'localhost',
45 | port: 1025,
46 | }
47 |
48 | # Print deprecation notices to the Rails logger.
49 | config.active_support.deprecation = :log
50 | default_url_options[:host]
51 | # Raise an error on page load if there are pending migrations.
52 | config.active_record.migration_error = :page_load
53 |
54 | # Highlight code that triggered database queries in logs.
55 | config.active_record.verbose_query_logs = true
56 |
57 |
58 | # Raises error for missing translations.
59 | # config.action_view.raise_on_missing_translations = true
60 |
61 | # Use an evented file watcher to asynchronously detect changes in source code,
62 | # routes, locales, etc. This feature depends on the listen gem.
63 | config.file_watcher = ActiveSupport::EventedFileUpdateChecker
64 |
65 | JUNO_AUTH_URL = "https://sandbox.boletobancario.com"
66 | JUNO_RESOURCE_URL = "https://sandbox.boletobancario.com/api-integration"
67 | end
68 |
--------------------------------------------------------------------------------
/config/environments/test.rb:
--------------------------------------------------------------------------------
1 | # The test environment is used exclusively to run your application's
2 | # test suite. You never need to work with it otherwise. Remember that
3 | # your test database is "scratch space" for the test suite and is wiped
4 | # and recreated between test runs. Don't rely on the data there!
5 |
6 | Rails.application.configure do
7 | # Settings specified here will take precedence over those in config/application.rb.
8 |
9 | config.cache_classes = false
10 | config.action_view.cache_template_loading = true
11 |
12 | # Do not eager load code on boot. This avoids loading your whole application
13 | # just for the purpose of running a single test. If you are using a tool that
14 | # preloads Rails for running tests, you may have to set it to true.
15 | config.eager_load = false
16 |
17 | # Configure public file server for tests with Cache-Control for performance.
18 | config.public_file_server.enabled = true
19 | config.public_file_server.headers = {
20 | 'Cache-Control' => "public, max-age=#{1.hour.to_i}"
21 | }
22 |
23 | # Show full error reports and disable caching.
24 | config.consider_all_requests_local = true
25 | config.action_controller.perform_caching = false
26 | config.cache_store = :null_store
27 |
28 | # Raise exceptions instead of rendering exception templates.
29 | config.action_dispatch.show_exceptions = false
30 |
31 | # Disable request forgery protection in test environment.
32 | config.action_controller.allow_forgery_protection = false
33 |
34 | # Store uploaded files on the local file system in a temporary directory.
35 | config.active_storage.service = :test
36 |
37 | config.action_mailer.perform_caching = false
38 |
39 | # Tell Action Mailer not to deliver emails to the real world.
40 | # The :test delivery method accumulates sent emails in the
41 | # ActionMailer::Base.deliveries array.
42 | config.action_mailer.delivery_method = :test
43 |
44 | config.action_mailer.default_url_options = { host: "http://localhost:3000" }
45 | Rails.application.routes.default_url_options[:host] = "http://localhost:3000"
46 |
47 | # Print deprecation notices to the stderr.
48 | config.active_support.deprecation = :stderr
49 |
50 | # Raises error for missing translations.
51 | # config.action_view.raise_on_missing_translations = true
52 |
53 | config.active_job.queue_adapter = :test
54 |
55 | JUNO_AUTH_URL = "https://sandbox.boletobancario.com"
56 | JUNO_RESOURCE_URL = "https://sandbox.boletobancario.com/api-integration"
57 | end
58 |
--------------------------------------------------------------------------------
/config/initializers/application_controller_renderer.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # ActiveSupport::Reloader.to_prepare do
4 | # ApplicationController.renderer.defaults.merge!(
5 | # http_host: 'example.org',
6 | # https: false
7 | # )
8 | # end
9 |
--------------------------------------------------------------------------------
/config/initializers/backtrace_silencers.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
5 |
6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
7 | # Rails.backtrace_cleaner.remove_silencers!
8 |
--------------------------------------------------------------------------------
/config/initializers/cors.rb:
--------------------------------------------------------------------------------
1 | Rails.application.config.middleware.insert_before 0, Rack::Cors do
2 | allow do
3 | origins '*'
4 | resource '*', headers: :any, methods: [:get, :post, :put, :patch, :delete],
5 | expose: ['access-token', 'client', 'expiry', 'token-type', 'uid']
6 | end
7 | end
--------------------------------------------------------------------------------
/config/initializers/filter_parameter_logging.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Configure sensitive parameters which will be filtered from the log file.
4 | Rails.application.config.filter_parameters += [:password]
5 |
--------------------------------------------------------------------------------
/config/initializers/inflections.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Add new inflection rules using the following format. Inflections
4 | # are locale specific, and you may define rules for as many different
5 | # locales as you wish. All of these examples are active by default:
6 | # ActiveSupport::Inflector.inflections(:en) do |inflect|
7 | # inflect.plural /^(ox)$/i, '\1en'
8 | # inflect.singular /^(ox)en/i, '\1'
9 | # inflect.irregular 'person', 'people'
10 | # inflect.uncountable %w( fish sheep )
11 | # end
12 |
13 | # These inflection rules are supported but not enabled by default:
14 | # ActiveSupport::Inflector.inflections(:en) do |inflect|
15 | # inflect.acronym 'RESTful'
16 | # end
17 |
--------------------------------------------------------------------------------
/config/initializers/mime_types.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Add new mime types for use in respond_to blocks:
4 | # Mime::Type.register "text/richtext", :rtf
5 |
--------------------------------------------------------------------------------
/config/initializers/wrap_parameters.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # This file contains settings for ActionController::ParamsWrapper which
4 | # is enabled by default.
5 |
6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
7 | ActiveSupport.on_load(:action_controller) do
8 | wrap_parameters format: [:json]
9 | end
10 |
11 | # To enable root element in JSON for ActiveRecord objects.
12 | # ActiveSupport.on_load(:active_record) do
13 | # self.include_root_in_json = true
14 | # end
15 |
--------------------------------------------------------------------------------
/config/locales/pt-BR/controllers/coupon_validations.yml:
--------------------------------------------------------------------------------
1 | pt-BR:
2 | storefront/v1/coupon_validations:
3 | create:
4 | failure: Cupom não pode ser utilizado
--------------------------------------------------------------------------------
/config/locales/pt-BR/custom_validations.yml:
--------------------------------------------------------------------------------
1 | pt-BR:
2 | activerecord:
3 | errors:
4 | messages:
5 | future_date: "deve ser uma data futura"
6 | invalid_cpf_cnpj: "deve ser um CPF ou CNPJ válido"
--------------------------------------------------------------------------------
/config/locales/pt-BR/mailers/checkout_mailer.yml:
--------------------------------------------------------------------------------
1 | pt-BR:
2 | checkout_mailer:
3 | success:
4 | subject: "Pedido #%{order_number} concluído com sucesso!"
5 | title: "Seu pedido #%{order_number} foi um sucesso!"
6 | body: |
7 | Obrigado por ter comprando com a gente!
8 | billet_payment:
9 | html: O seu boleto está neste link =D
10 | credit_card_payment: |
11 | O pagamento já foi um sucesso! Em breve vamos liberar o seu pedido =)
12 |
13 | generic_error:
14 | subject: "Ocorreu um erro com o seu pedido #%{order_number}"
15 | title: "Encontramos um erro ao processar o seu pedido #%{order_number}"
16 | body:
17 | html: |
18 | Infelizmente não conseguimos processar o seu pedido.
19 | Tente novamente daqui alguns minutos. Se o erro persistir o nosso suporte estará à sua disposição =)
20 |
21 | payment_error:
22 | subject: "Ocorreu um erro com o seu pedido #%{order_number}"
23 | title: "Encontramos um erro no pagamento do seu pedido #%{order_number}"
24 | body:
25 | html: |
26 | Infelizmente não conseguimos processar o seu pagamento.
27 | Ao tentarmos processar o seu pagamento, tivemos o seguinte status sobre o seu cartão: %{message}
--------------------------------------------------------------------------------
/config/locales/pt-BR/mailers/license_mailer.yml:
--------------------------------------------------------------------------------
1 | pt-BR:
2 | license_mailer:
3 | send_license:
4 | subject: Licença liberada! \o/
5 | title: A sua licença foi liberada
6 | body: |
7 | A licença para o jogo %{game_name} que você comprou está abaixo. Baixa você copiar e adicionar
8 | na sua plataforma jogos
--------------------------------------------------------------------------------
/config/locales/pt-BR/models/wish_item.yml:
--------------------------------------------------------------------------------
1 | pt-BR:
2 | activerecord:
3 | errors:
4 | models:
5 | wish_item:
6 | attributes:
7 | product_id:
8 | taken: "já está na lista do usuário"
--------------------------------------------------------------------------------
/config/locales/pt-BR/services/checkout_processor_service.yml:
--------------------------------------------------------------------------------
1 | pt-BR:
2 | storefront/checkout_processor_service:
3 | errors:
4 | items:
5 | presence: deve estar presente
6 | empty: não pode estar vazio
7 | coupon:
8 | invalid: não é valido
--------------------------------------------------------------------------------
/config/puma.rb:
--------------------------------------------------------------------------------
1 | # Puma can serve each request in a thread from an internal thread pool.
2 | # The `threads` method setting takes two numbers: a minimum and maximum.
3 | # Any libraries that use thread pools should be configured to match
4 | # the maximum value specified for Puma. Default is set to 5 threads for minimum
5 | # and maximum; this matches the default thread size of Active Record.
6 | #
7 | max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
8 | min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count }
9 | threads min_threads_count, max_threads_count
10 |
11 | # Specifies the `port` that Puma will listen on to receive requests; default is 3000.
12 | #
13 | port ENV.fetch("PORT") { 3000 }
14 |
15 | # Specifies the `environment` that Puma will run in.
16 | #
17 | environment ENV.fetch("RAILS_ENV") { "development" }
18 |
19 | # Specifies the `pidfile` that Puma will use.
20 | pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }
21 |
22 | # Specifies the number of `workers` to boot in clustered mode.
23 | # Workers are forked web server processes. If using threads and workers together
24 | # the concurrency of the application would be max `threads` * `workers`.
25 | # Workers do not work on JRuby or Windows (both of which do not support
26 | # processes).
27 | #
28 | # workers ENV.fetch("WEB_CONCURRENCY") { 2 }
29 |
30 | # Use the `preload_app!` method when specifying a `workers` number.
31 | # This directive tells Puma to first boot the application and load code
32 | # before forking the application. This takes advantage of Copy On Write
33 | # process behavior so workers use less memory.
34 | #
35 | # preload_app!
36 |
37 | # Allow puma to be restarted by `rails restart` command.
38 | plugin :tmp_restart
39 |
--------------------------------------------------------------------------------
/config/routes.rb:
--------------------------------------------------------------------------------
1 | require 'sidekiq/web'
2 | require 'sidekiq-scheduler/web'
3 | require_relative '../lib/middlewares/static_token_auth'
4 |
5 | Rails.application.routes.draw do
6 | Sidekiq::Web.use StaticTokenAuth
7 | mount Sidekiq::Web => '/sidekiq/:token'
8 |
9 | mount_devise_token_auth_for 'User', at: 'auth/v1/user'
10 |
11 | namespace :admin, defaults: { format: :json } do
12 | namespace :v1 do
13 | get "home" => "home#index"
14 | resources :categories
15 | resources :coupons
16 | resources :games, only: [], shallow: true do
17 | resources :licenses
18 | end
19 | resources :orders, only: [:index, :show]
20 | resources :products
21 | resources :system_requirements
22 | resources :users
23 |
24 | namespace :dashboard do
25 | resources :sales_ranges, only: :index
26 | resources :summaries, only: :index
27 | resources :top_five_products, only: :index
28 | end
29 | end
30 | end
31 |
32 | namespace :storefront, defaults: { format: :json } do
33 | namespace :v1 do
34 | get "home" => "home#index"
35 | resources :products, only: [:index, :show]
36 | resources :categories, only: :index
37 | resources :checkouts, only: :create
38 | post "/coupons/:coupon_code/validations", to: "coupon_validations#create"
39 | resources :games, only: :index
40 | resources :orders, only: [:index, :show]
41 | resources :wish_items, only: [:index, :create, :destroy]
42 | end
43 | end
44 |
45 | namespace :juno do
46 | namespace :v1 do
47 | resources :payment_confirmations, only: :create
48 | end
49 | end
50 | end
51 |
--------------------------------------------------------------------------------
/config/sidekiq.yml:
--------------------------------------------------------------------------------
1 | :schedule:
2 | Admin::FinishDeliveredOrdersJob:
3 | every: ['1h', first_in: '2m']
--------------------------------------------------------------------------------
/config/spring.rb:
--------------------------------------------------------------------------------
1 | Spring.watch(
2 | ".ruby-version",
3 | ".rbenv-vars",
4 | "tmp/restart.txt",
5 | "tmp/caching-dev.txt"
6 | )
7 |
--------------------------------------------------------------------------------
/config/storage.yml:
--------------------------------------------------------------------------------
1 | test:
2 | service: Disk
3 | root: <%= Rails.root.join("tmp/storage") %>
4 |
5 | local:
6 | service: Disk
7 | root: <%= Rails.root.join("storage") %>
8 |
9 | # Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key)
10 | # amazon:
11 | # service: S3
12 | # access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %>
13 | # secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %>
14 | # region: us-east-1
15 | # bucket: your_own_bucket
16 |
17 | # Remember not to checkin your GCS keyfile to a repository
18 | # google:
19 | # service: GCS
20 | # project: your_project
21 | # credentials: <%= Rails.root.join("path/to/gcs.keyfile") %>
22 | # bucket: your_own_bucket
23 |
24 | # Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key)
25 | # microsoft:
26 | # service: AzureStorage
27 | # storage_account_name: your_account_name
28 | # storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %>
29 | # container: your_container_name
30 |
31 | # mirror:
32 | # service: Mirror
33 | # primary: local
34 | # mirrors: [ amazon, google, microsoft ]
35 |
--------------------------------------------------------------------------------
/db/migrate/20200920200639_devise_token_auth_create_users.rb:
--------------------------------------------------------------------------------
1 | class DeviseTokenAuthCreateUsers < ActiveRecord::Migration[6.0]
2 | def change
3 |
4 | create_table(:users) do |t|
5 | ## Required
6 | t.string :provider, :null => false, :default => "email"
7 | t.string :uid, :null => false, :default => ""
8 |
9 | ## Database authenticatable
10 | t.string :encrypted_password, :null => false, :default => ""
11 |
12 | ## Recoverable
13 | t.string :reset_password_token
14 | t.datetime :reset_password_sent_at
15 | t.boolean :allow_password_change, :default => false
16 |
17 | ## Rememberable
18 | t.datetime :remember_created_at
19 |
20 | ## Confirmable
21 | t.string :confirmation_token
22 | t.datetime :confirmed_at
23 | t.datetime :confirmation_sent_at
24 | t.string :unconfirmed_email # Only if using reconfirmable
25 |
26 | ## Lockable
27 | # t.integer :failed_attempts, :default => 0, :null => false # Only if lock strategy is :failed_attempts
28 | # t.string :unlock_token # Only if unlock strategy is :email or :both
29 | # t.datetime :locked_at
30 |
31 | ## User Info
32 | t.string :name
33 | t.string :email
34 | t.integer :profile, default: 1
35 |
36 | ## Tokens
37 | t.json :tokens
38 |
39 | t.timestamps
40 | end
41 |
42 | add_index :users, :email, unique: true
43 | add_index :users, [:uid, :provider], unique: true
44 | add_index :users, :reset_password_token, unique: true
45 | add_index :users, :confirmation_token, unique: true
46 | # add_index :users, :unlock_token, unique: true
47 | end
48 | end
49 |
--------------------------------------------------------------------------------
/db/migrate/20200927152708_create_categories.rb:
--------------------------------------------------------------------------------
1 | class CreateCategories < ActiveRecord::Migration[6.0]
2 | def change
3 | create_table :categories do |t|
4 | t.string :name
5 |
6 | t.timestamps
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/db/migrate/20200927161952_create_products.rb:
--------------------------------------------------------------------------------
1 | class CreateProducts < ActiveRecord::Migration[6.0]
2 | def change
3 | create_table :products do |t|
4 | t.string :name
5 | t.text :description
6 | t.decimal :price, precision: 10, scale: 2
7 | t.references :productable, polymorphic: true, null: false
8 |
9 | t.timestamps
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/db/migrate/20200927162631_create_product_categories.rb:
--------------------------------------------------------------------------------
1 | class CreateProductCategories < ActiveRecord::Migration[6.0]
2 | def change
3 | create_table :product_categories do |t|
4 | t.references :product, null: false, foreign_key: true
5 | t.references :category, null: false, foreign_key: true
6 |
7 | t.timestamps
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/db/migrate/20200927171715_create_system_requirements.rb:
--------------------------------------------------------------------------------
1 | class CreateSystemRequirements < ActiveRecord::Migration[6.0]
2 | def change
3 | create_table :system_requirements do |t|
4 | t.string :name
5 | t.string :operational_system
6 | t.string :storage
7 | t.string :processor
8 | t.string :memory
9 | t.string :video_board
10 |
11 | t.timestamps
12 | end
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/db/migrate/20200927173409_create_games.rb:
--------------------------------------------------------------------------------
1 | class CreateGames < ActiveRecord::Migration[6.0]
2 | def change
3 | create_table :games do |t|
4 | t.integer :mode
5 | t.datetime :release_date
6 | t.string :developer
7 | t.references :system_requirement, null: false, foreign_key: true
8 |
9 | t.timestamps
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/db/migrate/20200927192509_create_coupons.rb:
--------------------------------------------------------------------------------
1 | class CreateCoupons < ActiveRecord::Migration[6.0]
2 | def change
3 | create_table :coupons do |t|
4 | t.string :name
5 | t.string :code
6 | t.integer :status
7 | t.decimal :discount_value, precision: 5, scale: 2
8 | t.datetime :due_date
9 |
10 | t.timestamps
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/db/migrate/20201018131945_create_active_storage_tables.active_storage.rb:
--------------------------------------------------------------------------------
1 | # This migration comes from active_storage (originally 20170806125915)
2 | class CreateActiveStorageTables < ActiveRecord::Migration[5.2]
3 | def change
4 | create_table :active_storage_blobs do |t|
5 | t.string :key, null: false
6 | t.string :filename, null: false
7 | t.string :content_type
8 | t.text :metadata
9 | t.bigint :byte_size, null: false
10 | t.string :checksum, null: false
11 | t.datetime :created_at, null: false
12 |
13 | t.index [ :key ], unique: true
14 | end
15 |
16 | create_table :active_storage_attachments do |t|
17 | t.string :name, null: false
18 | t.references :record, null: false, polymorphic: true, index: false
19 | t.references :blob, null: false
20 |
21 | t.datetime :created_at, null: false
22 |
23 | t.index [ :record_type, :record_id, :name, :blob_id ], name: "index_active_storage_attachments_uniqueness", unique: true
24 | t.foreign_key :active_storage_blobs, column: :blob_id
25 | end
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/db/migrate/20201122234724_add_status_to_products.rb:
--------------------------------------------------------------------------------
1 | class AddStatusToProducts < ActiveRecord::Migration[6.0]
2 | def change
3 | add_column :products, :status, :integer
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20210107010752_create_licenses.rb:
--------------------------------------------------------------------------------
1 | class CreateLicenses < ActiveRecord::Migration[6.0]
2 | def change
3 | create_table :licenses do |t|
4 | t.string :key
5 | t.integer :platform
6 | t.integer :status
7 | t.references :game, null: false, foreign_key: true
8 |
9 | t.timestamps
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/db/migrate/20210110175644_create_wish_items.rb:
--------------------------------------------------------------------------------
1 | class CreateWishItems < ActiveRecord::Migration[6.0]
2 | def change
3 | create_table :wish_items do |t|
4 | t.references :user, null: false, foreign_key: true
5 | t.references :product, null: false, foreign_key: true
6 |
7 | t.timestamps
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/db/migrate/20210114010037_add_featured_to_products.rb:
--------------------------------------------------------------------------------
1 | class AddFeaturedToProducts < ActiveRecord::Migration[6.0]
2 | def change
3 | add_column :products, :featured, :boolean, default: false
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20210207154531_create_orders.rb:
--------------------------------------------------------------------------------
1 | class CreateOrders < ActiveRecord::Migration[6.0]
2 | def change
3 | create_table :orders do |t|
4 | t.integer :status
5 | t.decimal :subtotal, precision: 10, scale: 2
6 | t.decimal :total_amount, precision: 10, scale: 2
7 | t.integer :payment_type
8 | t.integer :installments
9 | t.references :user, null: false, foreign_key: true
10 | t.references :coupon, null: true, foreign_key: true
11 |
12 | t.timestamps
13 | end
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/db/migrate/20210209120441_create_line_items.rb:
--------------------------------------------------------------------------------
1 | class CreateLineItems < ActiveRecord::Migration[6.0]
2 | def change
3 | create_table :line_items do |t|
4 | t.integer :quantity
5 | t.decimal :payed_price, precision: 10, scale: 2
6 | t.references :order, null: false, foreign_key: true
7 | t.references :product, null: false, foreign_key: true
8 |
9 | t.timestamps
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/db/migrate/20210306190339_create_juno_charges.rb:
--------------------------------------------------------------------------------
1 | class CreateJunoCharges < ActiveRecord::Migration[6.0]
2 | def change
3 | create_table :juno_charges do |t|
4 | t.string :key
5 | t.string :code
6 | t.string :number
7 | t.decimal :amount, precision: 10, scale: 2
8 | t.string :status
9 | t.string :billet_url
10 | t.references :order, null: false, foreign_key: true
11 |
12 | t.timestamps
13 | end
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/db/migrate/20210306200906_create_juno_credit_card_payments.rb:
--------------------------------------------------------------------------------
1 | class CreateJunoCreditCardPayments < ActiveRecord::Migration[6.0]
2 | def change
3 | create_table :juno_credit_card_payments do |t|
4 | t.string :key
5 | t.datetime :release_date
6 | t.string :status
7 | t.string :reason
8 | t.references :charge, null: false, foreign_key: { to_table: :juno_charges }
9 |
10 | t.timestamps
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/db/migrate/20210314134141_add_line_item_reference_to_licenses.rb:
--------------------------------------------------------------------------------
1 | class AddLineItemReferenceToLicenses < ActiveRecord::Migration[6.0]
2 | def change
3 | add_reference :licenses, :line_item, foreign_key: true
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20210315110855_add_status_to_line_items.rb:
--------------------------------------------------------------------------------
1 | class AddStatusToLineItems < ActiveRecord::Migration[6.0]
2 | def change
3 | add_column :line_items, :status, :integer
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/seeds.rb:
--------------------------------------------------------------------------------
1 | # This file should contain all the record creation needed to seed the database with its default values.
2 | # The data can then be loaded with the rails db:seed command (or created alongside the database with db:setup).
3 | #
4 | # Examples:
5 | #
6 | # movies = Movie.create([{ name: 'Star Wars' }, { name: 'Lord of the Rings' }])
7 | # Character.create(name: 'Luke', movie: movies.first)
8 |
--------------------------------------------------------------------------------
/lib/juno_api/auth.rb:
--------------------------------------------------------------------------------
1 | module JunoApi
2 | class Auth
3 | include HTTParty
4 |
5 | PATH = "/authorization-server/oauth/token"
6 | SECONDS_TO_WAIT_PROCESSING = 0.5
7 | LIMIT_RATE_TO_RENEW = 90
8 |
9 | base_uri "#{JUNO_AUTH_URL}"
10 |
11 | attr_reader :access_token, :expires_in, :request_time
12 | private_class_method :new
13 |
14 | def self.singleton
15 | wait_until_process_is_done
16 | check_instance
17 | @instance
18 | end
19 |
20 | private
21 |
22 | def self.wait_until_process_is_done
23 | while @processing
24 | sleep SECONDS_TO_WAIT_PROCESSING
25 | end
26 | end
27 |
28 | def self.check_instance
29 | if @instance.blank? || is_about_to_expire?(@instance)
30 | @processing = true
31 | @instance = new
32 | @processing = false
33 | end
34 | end
35 |
36 | def self.is_about_to_expire?(instance)
37 | expiration_rate = LIMIT_RATE_TO_RENEW / 100.0
38 | instance.request_time + instance.expires_in * expiration_rate < Time.zone.now
39 | end
40 |
41 | def initialize
42 | auth = process_auth!
43 | @access_token = auth['access_token']
44 | @expires_in = auth['expires_in']
45 | @request_time = Time.zone.now
46 | end
47 |
48 | def process_auth!
49 | body = { grant_type: 'client_credentials' }
50 | response = self.class.post(PATH, headers: { 'Authorization' => 'Basic ' + auth_token }, body: body )
51 | raise Error.new("Bad request") if response.code != 200
52 | response.parsed_response
53 | end
54 |
55 | def auth_token
56 | auth_data = Rails.application.credentials.juno.slice(:client, :secret)
57 | Base64.strict_encode64(auth_data[:client] + ":" + auth_data[:secret])
58 | end
59 | end
60 | end
--------------------------------------------------------------------------------
/lib/juno_api/charge.rb:
--------------------------------------------------------------------------------
1 | require_relative "./auth"
2 | require_relative "./request_error"
3 |
4 | module JunoApi
5 | class Charge
6 | include HTTParty
7 |
8 | PAYMENT_TYPE = { 'billet' => "BOLETO", 'credit_card' =>"CREDIT_CARD" }
9 | CHARGE_KEYS_TO_KEEP = %i[id code installment_link amount status]
10 |
11 | base_uri "#{JUNO_RESOURCE_URL}/charges"
12 |
13 | headers 'Content-Type' => 'application/json'
14 | headers 'X-Api-Version' => '2'
15 | headers 'X-Resource-Token' => Rails.application.credentials.juno[:private_token]
16 |
17 | def initialize
18 | @auth = Auth.singleton
19 | end
20 |
21 | def create!(order)
22 | auth_header = { 'Authorization' => "Bearer #{auth.access_token}" }
23 | body = prepare_create_body(order)
24 | response = self.class.post("/", headers: auth_header, body: body.to_json)
25 | raise_error(response) if response.code != 200
26 | organize_response(response)
27 | end
28 |
29 | private
30 |
31 | attr_reader :auth, :auth_header
32 |
33 | def prepare_create_body(order)
34 | {
35 | charge: build_charge(order),
36 | billing: { name: order.user.name, document: order.document, email: order.user.email }
37 | }
38 | end
39 |
40 | def raise_error(response)
41 | details = response.parsed_response['details'].map { |detail| detail.transform_keys(&:underscore) }
42 | raise RequestError.new("Invalid request sent to Juno", details)
43 | rescue NoMethodError => e
44 | raise RequestError.new("Invalid request sent to Juno")
45 | end
46 |
47 | def organize_response(response)
48 | response.parsed_response['_embedded']['charges'].map do |charge|
49 | charge.deep_transform_keys! { |key| key.underscore.to_sym }
50 | charge.keep_if { |key, _| CHARGE_KEYS_TO_KEEP.include?(key) }
51 | end
52 | end
53 |
54 | def build_charge(order)
55 | {
56 | description: "Order ##{order.id}", amount: (order.total_amount / order.installments).floor(2),
57 | dueDate: order.due_date.strftime("%Y-%m-%d"), installments: order.installments,
58 | discountAmount: (order.coupon&.discount_value).to_f, paymentTypes: [PAYMENT_TYPE[order.payment_type]]
59 | }
60 | end
61 | end
62 | end
--------------------------------------------------------------------------------
/lib/juno_api/credit_card_payment.rb:
--------------------------------------------------------------------------------
1 | require_relative "./auth"
2 | require_relative "./request_error"
3 |
4 | module JunoApi
5 | class CreditCardPayment
6 | include HTTParty
7 |
8 | base_uri "#{JUNO_RESOURCE_URL}/payments"
9 |
10 | headers 'Content-Type' => 'application/json'
11 | headers 'X-Api-Version' => '2'
12 | headers 'X-Resource-Token' => Rails.application.credentials.juno[:private_token]
13 |
14 | def initialize
15 | @auth = Auth.singleton
16 | end
17 |
18 | def create!(order)
19 | auth_header = { 'Authorization' => "Bearer #{auth.access_token}" }
20 | body = prepare_create_body(order, order.juno_charges.first.key)
21 | response = self.class.post("/", headers: auth_header, body: body.to_json)
22 | raise_error(response) if response.code != 200
23 | organize_response(response)
24 | end
25 |
26 | private
27 |
28 | attr_reader :auth
29 |
30 | def prepare_create_body(order, charge_key)
31 | {
32 | chargeId: charge_key,
33 | creditCardDetails: { creditCardHash: order.card_hash },
34 | billing: { email: order.user.email, address: build_address_attributes(order.address) }
35 | }
36 | end
37 |
38 | def raise_error(response)
39 | details = response.parsed_response['details'].map { |detail| detail.transform_keys(&:underscore) }
40 | raise RequestError.new("Invalid request sent to Juno", details)
41 | rescue NoMethodError => e
42 | raise RequestError.new("Invalid request sent to Juno")
43 | end
44 |
45 | def organize_response(response)
46 | response.parsed_response['payments'].map do |payment|
47 | {
48 | key: payment['id'], charge: payment['chargeId'], release_date: payment['releaseDate'],
49 | status: payment['status'], reason: payment['failReason']
50 | }
51 | end
52 | end
53 |
54 | def build_address_attributes(address)
55 | address.attributes.transform_keys { |key| key.camelize(:lower) }
56 | end
57 | end
58 | end
--------------------------------------------------------------------------------
/lib/juno_api/request_error.rb:
--------------------------------------------------------------------------------
1 | module JunoApi
2 | class RequestError < StandardError
3 | attr_reader :error
4 |
5 | def initialize(message, error = nil)
6 | @error = error
7 | super(message)
8 | end
9 | end
10 | end
--------------------------------------------------------------------------------
/lib/middlewares/static_token_auth.rb:
--------------------------------------------------------------------------------
1 | class StaticTokenAuth
2 | TOKEN_TO_VERIFY = Rails.application.credentials.token[:sidekiq]
3 |
4 | def initialize(app)
5 | @app = app
6 | end
7 |
8 | def call(env)
9 | token = env.dig('action_dispatch.request.path_parameters', :token)
10 | if token == TOKEN_TO_VERIFY
11 | return @app.call(env)
12 | end
13 | [401, {}, ['Invalid Token']]
14 | end
15 | end
--------------------------------------------------------------------------------
/lib/tasks/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OneBitCodeBlog/e-commerce-Api-Dev/cf15a94a7f2f7ac43089ab4cdb7e7176afbc8bee/lib/tasks/.keep
--------------------------------------------------------------------------------
/lib/tasks/dev/prime.rake:
--------------------------------------------------------------------------------
1 | if Rails.env.development? || Rails.env.test?
2 | require 'factory_bot'
3 |
4 | namespace :dev do
5 | desc 'Sample data for local development environment'
6 | task prime: 'db:setup' do
7 | include FactoryBot::Syntax::Methods
8 |
9 | 15.times do
10 | profile = [:admin, :client].sample
11 | create(:user, profile: profile)
12 | end
13 |
14 | system_requirements = []
15 | ['Basic', 'Intermediate', 'Advanced'].each do |sr_name|
16 | system_requirements << create(:system_requirement, name: sr_name)
17 | end
18 |
19 | 15.times do
20 | coupon_status = [:active, :inactive].sample
21 | create(:coupon, status: coupon_status)
22 | end
23 |
24 | categories = []
25 | 25.times do
26 | categories << create(:category, name: Faker::Game.unique.genre)
27 | end
28 |
29 | 30.times do
30 | game_name = Faker::Game.unique.title
31 | availability = [:available, :unavailable].sample
32 | categories_count = rand(0..3)
33 | featured = [true, false].sample
34 | price = Faker::Commerce.price(range: 5.0..30.0)
35 | release_date = (0..15).to_a.sample.days.ago
36 | game_categories_ids = []
37 | categories_count.times { game_categories_ids << Category.all.sample.id }
38 | game = create(:game, system_requirement: system_requirements.sample, release_date: release_date)
39 | create(:product, name: game_name, status: availability, featured: featured, price: price,
40 | category_ids: game_categories_ids, productable: game)
41 | end
42 |
43 | 50.times do
44 | game = Game.all[0...5].sample
45 | status = [:available, :inactive].sample
46 | platform = [:steam, :battle_net, :origin].sample
47 | create(:license, status: status, platform: platform, game: game)
48 | end
49 |
50 | 10.times do
51 | product = Product.all.sample
52 | (1..10).to_a.sample.times do
53 | product.wish_items.create(user: User.all.sample)
54 | end
55 | end
56 | end
57 | end
58 | end
--------------------------------------------------------------------------------
/log/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OneBitCodeBlog/e-commerce-Api-Dev/cf15a94a7f2f7ac43089ab4cdb7e7176afbc8bee/log/.keep
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file
2 |
--------------------------------------------------------------------------------
/spec/factories/addresses.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :address do
3 | street { Faker::Address.street_name }
4 | number { Faker::Address.building_number }
5 | city { Faker::Address.city }
6 | state { Faker::Address.state_abbr }
7 | post_code { Faker::Address.postcode }
8 |
9 | skip_create
10 | initialize_with { new(**attributes) }
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/spec/factories/categories.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :category do
3 | sequence(:name) { |n| "Category #{n}" }
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/spec/factories/coupons.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :coupon do
3 | sequence(:name) { |n| "My Coupon #{n}" }
4 | code { Faker::Commerce.unique.promotion_code(digits: 4) }
5 | status { :active }
6 | discount_value { 25 }
7 | due_date { 3.days.from_now }
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/spec/factories/games.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :game do
3 | mode { %i(pvp pve both).sample }
4 | release_date { '2020-06-01' }
5 | developer { Faker::Company.name }
6 | system_requirement
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/spec/factories/juno/charges.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :juno_charge, class: 'Juno::Charge' do
3 | key { "chr_#{Faker::Lorem.characters(number: 20) }" }
4 | code { Faker::Number.number(digits: 20) }
5 | sequence(:number) { |n| n }
6 | amount { Faker::Commerce.price(range: 40..100) }
7 | status { "ACTIVE" }
8 | billet_url { Faker::Internet.url(host: 'pay.juno.com') }
9 | order
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/spec/factories/juno/credit_card_payments.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :juno_credit_card_payment, class: 'Juno::CreditCardPayment' do
3 | key { "pay_#{Faker::Lorem.characters(number: 20) }" }
4 | release_date { 1.month.from_now }
5 | status { "CONFIRMED" }
6 | reason { nil }
7 | charge { association :juno_charge }
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/spec/factories/licenses.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :license do
3 | key { Faker::Lorem.characters(number: 15) }
4 | platform { :steam }
5 | status { :available }
6 | game
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/spec/factories/line_items.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :line_item do
3 | quantity { 1 }
4 | payed_price { Faker::Commerce.price(range: 100.00..200.00) }
5 | status { :waiting_order }
6 | order
7 | product
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/spec/factories/orders.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :order do
3 | status { :processing_order }
4 | subtotal { Faker::Commerce.price(range: 200.00..400.00) }
5 | total_amount { subtotal }
6 | payment_type { :credit_card }
7 | card_hash { Faker::Lorem.characters }
8 | installments { 5 }
9 | address { build(:address) }
10 | document { "03.000.050/0001-67" }
11 | user
12 |
13 | trait :with_items do
14 | after :build do |order|
15 | items = create_list(:line_items, 5, order: order)
16 | order.subtotal = items.sum(:payed_price)
17 | order.total_amount = order.subtotal
18 | end
19 | end
20 |
21 | trait :with_coupon do
22 | after :build do |order|
23 | coupon = create(:coupon, discount_value: 10)
24 | order.total_amout = order.subtotal * (1 - coupon.discount_value / 100)
25 | end
26 | end
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/spec/factories/product_categories.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :product_category do
3 | product
4 | category
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/spec/factories/products.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :product do
3 | sequence(:name) { |n| "Product #{n}" }
4 | description { Faker::Lorem.paragraph }
5 | price { Faker::Commerce.price(range: 100.0..400.0) }
6 | image { Rack::Test::UploadedFile.new(Rails.root.join("spec/support/images/product_image.png")) }
7 | status { :available }
8 | featured { true }
9 |
10 | after :build do |product|
11 | product.productable ||= create(:game)
12 | end
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/spec/factories/system_requirements.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :system_requirement do
3 | sequence(:name) { |n| "Basic #{n}" }
4 | operational_system { Faker::Computer.os }
5 | storage { "5GB" }
6 | processor { "AMD Ryzen 7" }
7 | memory { "2GB" }
8 | video_board { "N/A" }
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/spec/factories/users.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :user do
3 | name { Faker::Name.name }
4 | email { Faker::Internet.email }
5 | password { "123456" }
6 | password_confirmation { "123456" }
7 | profile { :admin }
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/spec/factories/wish_items.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :wish_item do
3 | user
4 | product
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/spec/libs/juno_api/auth_spec.rb:
--------------------------------------------------------------------------------
1 | require "rails_helper"
2 | require_relative "../../../lib/juno_api/auth"
3 |
4 | describe JunoApi::Auth do
5 | let(:auth_class) { JunoApi::Auth.clone }
6 |
7 | context "when call #singleton" do
8 | let(:response) do
9 | double(
10 | parsed_response: { 'access_token' => SecureRandom.hex, 'expires_in' => 1.day.from_now.to_i },
11 | code: 200
12 | )
13 | end
14 |
15 | it "returns only one instance" do
16 | allow(auth_class).to receive(:post).and_return(response)
17 | object_ids = 0.upto(4).collect do
18 | auth_class.singleton
19 | end
20 | object_ids.uniq!
21 | expect(object_ids.size).to eq 1
22 | end
23 |
24 | it "call Juno API only once" do
25 | allow(auth_class).to receive(:post).and_return(response).once
26 | object_ids = 0.upto(4).collect do
27 | auth_class.singleton
28 | end
29 | end
30 | end
31 |
32 | context "when call #access_token" do
33 | let(:first_response) do
34 | double(
35 | parsed_response: { 'access_token' => SecureRandom.hex, 'expires_in' => 1.day },
36 | code: 200
37 | )
38 | end
39 |
40 | let(:second_response) do
41 | double(
42 | parsed_response: { 'access_token' => SecureRandom.hex, 'expires_in' => 1.day },
43 | code: 200
44 | )
45 | end
46 |
47 | before(:each) do
48 | allow(auth_class).to receive(:post).and_return(first_response, second_response)
49 | end
50 |
51 | it "returns same access token before expiration" do
52 | first_auth = auth_class.singleton
53 | second_auth = auth_class.singleton
54 | expect(first_auth.access_token).to eq second_auth.access_token
55 | end
56 |
57 | it "returns another access token when it is expired" do
58 | first_auth = auth_class.singleton
59 | travel 3.days do
60 | second_auth = auth_class.singleton
61 | expect(first_auth.access_token).to_not eq second_auth.access_token
62 | end
63 | end
64 |
65 | it "returns another access token it reaches expiration rate" do
66 | first_auth = auth_class.singleton
67 | seconds_to_travel = first_auth.expires_in * 0.91
68 | travel seconds_to_travel.seconds do
69 | second_auth = auth_class.singleton
70 | expect(first_auth.access_token).to_not eq second_auth.access_token
71 | end
72 | end
73 | end
74 | end
--------------------------------------------------------------------------------
/spec/libs/juno_api/charge_spec.rb:
--------------------------------------------------------------------------------
1 | require "rails_helper"
2 | require_relative "../../../lib/juno_api/charge"
3 |
4 | describe JunoApi::Charge do
5 | let!(:order) { create(:order) }
6 |
7 | describe "#create" do
8 | before(:each) do
9 | singleton = double(access_token: SecureRandom.hex)
10 | allow(JunoApi::Auth).to receive(:singleton).and_return(singleton)
11 | end
12 |
13 | context "with invalid params" do
14 | it "should raise an error" do
15 | error = { details: [{ message: "Some error", errorCode: "10000" }] }.to_json
16 | error_response = double(code: 400, body: error, parsed_response: JSON.parse(error))
17 | allow(JunoApi::Charge).to receive(:post).and_return(error_response)
18 | expect do
19 | described_class.new.create!(order)
20 | end.to raise_error(JunoApi::RequestError)
21 | end
22 | end
23 |
24 | context "with valid params" do
25 | let(:return_from_api) do
26 | installment_to_pay = (order.total_amount / order.installments).floor(2)
27 | charges = 0.upto(order.installments - 1).map do |num|
28 | {
29 | id: "000#{num}", code: num, dueDate: (order.due_date + num.months).strftime("%Y-%m-%d"),
30 | reference: "", amount: installment_to_pay, checkoutUrl: Faker::Internet.url(host: 'checkout.juno.com'),
31 | status: "ACTIVE", _links: { self: { href: Faker::Internet.url(host: 'checkout.juno.com') } }
32 | }
33 | end
34 | { _embedded: { charges: charges } }.to_json
35 | end
36 |
37 | before(:each) do
38 | api_response = double(code: 200, body: return_from_api, parsed_response: JSON.parse(return_from_api))
39 | allow(JunoApi::Charge).to receive(:post).and_return(api_response)
40 | end
41 |
42 | it "returns same quantity of charges as installments" do
43 | charges = described_class.new.create!(order)
44 | expect(charges.count).to eq order.installments
45 | end
46 |
47 | it "return all charges with same installment amout" do
48 | charges = described_class.new.create!(order)
49 | installment_amount = charges.map { |charge| charge[:amount] }.uniq
50 | expect(installment_amount.size).to eq 1
51 | end
52 |
53 |
54 | it "return right amount on each installment" do
55 | installment_for_payment = (order.total_amount / order.installments.to_f).floor(2).to_f
56 | charges = described_class.new.create!(order)
57 | charges.each do |charge|
58 | expect(charge[:amount].to_f).to eq installment_for_payment
59 | end
60 | end
61 | end
62 | end
63 | end
--------------------------------------------------------------------------------
/spec/libs/juno_api/credit_card_payment_spec.rb:
--------------------------------------------------------------------------------
1 | require "rails_helper"
2 | require_relative "../../../lib/juno_api/credit_card_payment"
3 |
4 | describe JunoApi::CreditCardPayment do
5 | let!(:order) { create(:order) }
6 |
7 | describe "#create" do
8 | let!(:order) { create(:order) }
9 | let!(:charges) { create_list(:juno_charge, 5, order: order) }
10 |
11 | before(:each) do
12 | singleton = double(access_token: SecureRandom.hex)
13 | allow(JunoApi::Auth).to receive(:singleton).and_return(singleton)
14 | end
15 |
16 | context "with invalid params" do
17 | it "should raise an error" do
18 | error = { details: [{ message: "Some error", errorCode: "10000" }] }.to_json
19 | error_response = double(code: 400, body: error, parsed_response: JSON.parse(error))
20 | allow(JunoApi::CreditCardPayment).to receive(:post).and_return(error_response)
21 | expect do
22 | described_class.new.create!(order)
23 | end.to raise_error(JunoApi::RequestError)
24 | end
25 | end
26 |
27 | context "with valid params" do
28 | let(:return_from_api) do
29 | payments = charges.map.with_index do |charge, index|
30 | release_date = (Time.zone.now + index.months).strftime("%Y-%m-%d")
31 | {
32 | id: "pay_000#{index}", chargeId: charge.key, date: Time.zone.now.strftime("%Y-%m-%d"),
33 | releaseDate: release_date, amount: charge.amount.to_f, fee: 2, type: "INSTALLMENT_CREDIT_CARD",
34 | status: "CONFIRMED", failReason: nil
35 | }
36 | end
37 | { transactionId: SecureRandom.hex, installments: charges.count, payments: payments }.to_json
38 | end
39 |
40 | before(:each) do
41 | api_response = double(code: 200, body: return_from_api, parsed_response: JSON.parse(return_from_api))
42 | allow(JunoApi::CreditCardPayment).to receive(:post).and_return(api_response)
43 | end
44 |
45 | it "returns same quantity of charges" do
46 | payments = described_class.new.create!(order)
47 | expect(payments.count).to eq charges.count
48 | end
49 |
50 | it "return expected payments hash" do
51 | expected_payments = charges.map.with_index do |charge, index|
52 | release_date = (Time.zone.now + index.months).strftime("%Y-%m-%d")
53 | { key: "pay_000#{index}", charge: charge.key, release_date: release_date, status: "CONFIRMED", reason: nil }
54 | end
55 | payments = described_class.new.create!(order)
56 | expect(payments).to eq expected_payments
57 | end
58 | end
59 | end
60 | end
--------------------------------------------------------------------------------
/spec/libs/middlewares/static_token_auth_spec.rb:
--------------------------------------------------------------------------------
1 | require "rails_helper"
2 |
3 | describe StaticTokenAuth do
4 | let(:app) { ->(env){ [200, env, "my middleware spec"] } }
5 | let(:token) { Rails.application.credentials.token[:sidekiq] }
6 |
7 | it "returns 401 when it does not have any token" do
8 | env_mock = Rack::MockRequest.env_for("my.testing.com")
9 | middleware = described_class.new(app)
10 | response = middleware.call(env_mock)
11 | expect(response.first).to eq 401
12 | end
13 |
14 | it "returns 401 when token is invalid" do
15 | env_mock = Rack::MockRequest.env_for("my.testing.com")
16 | env_mock['action_dispatch.request.path_parameters'] = { token: 'some_random_token' }
17 | middleware = described_class.new(app)
18 | response = middleware.call(env_mock)
19 | expect(response.first).to eq 401
20 | end
21 |
22 | it "returns 200 when token is valid" do
23 | env_mock = Rack::MockRequest.env_for("my.testing.com")
24 | env_mock['action_dispatch.request.path_parameters'] = { token: token }
25 | middleware = described_class.new(app)
26 | response = middleware.call(env_mock)
27 | expect(response.first).to eq 200
28 | end
29 | end
--------------------------------------------------------------------------------
/spec/models/address_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe Address, type: :model do
4 | it { is_expected.to validate_presence_of(:street) }
5 | it { is_expected.to validate_presence_of(:number) }
6 | it { is_expected.to validate_presence_of(:city) }
7 | it { is_expected.to validate_presence_of(:state) }
8 | it { is_expected.to validate_presence_of(:post_code) }
9 | end
10 |
--------------------------------------------------------------------------------
/spec/models/category_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe Category, type: :model do
4 | it { is_expected.to validate_presence_of(:name) }
5 | it { is_expected.to validate_uniqueness_of(:name).case_insensitive }
6 |
7 | it { is_expected.to have_many(:product_categories).dependent(:destroy) }
8 | it { is_expected.to have_many(:products).through(:product_categories) }
9 |
10 | it_has_behavior_of "like searchable concern", :category, :name
11 | it_behaves_like "paginatable concern", :category
12 | end
13 |
--------------------------------------------------------------------------------
/spec/models/coupon_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe Coupon, type: :model do
4 | it { is_expected.to validate_presence_of :name }
5 | it { is_expected.to validate_presence_of :code }
6 | it { is_expected.to validate_uniqueness_of(:code).case_insensitive }
7 | it { is_expected.to validate_presence_of :status }
8 | it { is_expected.to define_enum_for(:status).with_values({ active: 1, inactive: 2 }) }
9 | it { is_expected.to validate_presence_of :discount_value }
10 | it { is_expected.to validate_numericality_of(:discount_value).is_greater_than(0) }
11 | it { is_expected.to validate_presence_of :due_date }
12 |
13 | it "can't have past due_date" do
14 | subject.due_date = 1.day.ago
15 | subject.valid?
16 | expect(subject.errors.keys).to include :due_date
17 | end
18 |
19 | it "is invalid with current due_date" do
20 | subject.due_date = Time.zone.now
21 | subject.valid?
22 | expect(subject.errors.keys).to include :due_date
23 | end
24 |
25 | it "is valid with future date" do
26 | subject.due_date = Time.zone.now + 1.hour
27 | subject.valid?
28 | expect(subject.errors.keys).to_not include :due_date
29 | end
30 |
31 | context "on #validate_use!" do
32 | subject { build(:coupon) }
33 |
34 | it "raise InvalidUse when it's overdue" do
35 | subject.due_date = 2.days.ago
36 | expect do
37 | subject.validate_use!
38 | end.to raise_error(Coupon::InvalidUse)
39 | end
40 |
41 | it "raise InvalidUse when it's inactive" do
42 | subject.status = :inactive
43 | expect do
44 | subject.validate_use!
45 | end.to raise_error(Coupon::InvalidUse)
46 | end
47 |
48 | it "returns true when it's on date and active" do
49 | expect(subject.validate_use!).to eq true
50 | end
51 | end
52 |
53 | it_has_behavior_of "like searchable concern", :coupon, :name
54 | it_behaves_like "paginatable concern", :coupon
55 | end
56 |
--------------------------------------------------------------------------------
/spec/models/game_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe Game, type: :model do
4 | it { is_expected.to validate_presence_of(:mode) }
5 | it { is_expected.to define_enum_for(:mode).with_values({ pvp: 1, pve: 2, both: 3 }) }
6 | it { is_expected.to validate_presence_of(:release_date) }
7 | it { is_expected.to validate_presence_of(:developer) }
8 |
9 | it { is_expected.to belong_to :system_requirement }
10 | it { is_expected.to have_one :product }
11 | it { is_expected.to have_many :licenses }
12 |
13 | it_has_behavior_of "like searchable concern", :game, :developer
14 |
15 | it "#ship! must schedule job AlocateLicenseJob sending Line Item" do
16 | subject.product = create(:product)
17 | line_item = create(:line_item, product: subject.product)
18 | expect do
19 | subject.ship!(line_item)
20 | end.to have_enqueued_job(Admin::AlocateLicenseJob).with(line_item)
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/spec/models/juno/charge_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe Juno::Charge, type: :model do
4 | subject { build(:juno_charge) }
5 |
6 | it { is_expected.to belong_to :order }
7 | it { is_expected.to have_many :credit_card_payments }
8 |
9 | it { is_expected.to validate_presence_of :key }
10 | it { is_expected.to validate_presence_of :code }
11 | it { is_expected.to validate_presence_of(:number) }
12 | it { is_expected.to validate_uniqueness_of(:number).scoped_to(:order_id).case_insensitive }
13 | it { is_expected.to validate_numericality_of(:number).is_greater_than(0).only_integer }
14 | it { is_expected.to validate_presence_of(:amount) }
15 | it { is_expected.to validate_numericality_of(:amount).is_greater_than(0) }
16 | it { is_expected.to validate_presence_of :status }
17 | end
18 |
--------------------------------------------------------------------------------
/spec/models/juno/credit_card_payment_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe Juno::CreditCardPayment, type: :model do
4 | it { is_expected.to belong_to :charge }
5 |
6 | it { is_expected.to validate_presence_of :key }
7 | it { is_expected.to validate_presence_of :release_date }
8 | it { is_expected.to validate_presence_of :status }
9 | end
10 |
--------------------------------------------------------------------------------
/spec/models/license_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe License, type: :model do
4 | subject { build(:license) }
5 |
6 | it { is_expected.to belong_to :game }
7 | it { is_expected.to belong_to(:line_item).optional }
8 |
9 | it { is_expected.to validate_presence_of(:key) }
10 | it { is_expected.to validate_uniqueness_of(:key).case_insensitive.scoped_to(:platform) }
11 | it { is_expected.to validate_presence_of(:platform) }
12 | it { is_expected.to define_enum_for(:platform).with_values({ steam: 1, battle_net: 2, origin: 3 }) }
13 | it { is_expected.to validate_presence_of(:status) }
14 | it { is_expected.to define_enum_for(:status).with_values({ available: 1, in_use: 2, inactive: 3 }) }
15 |
16 | it_behaves_like "paginatable concern", :license
17 | it_has_behavior_of "like searchable concern", :license, :key
18 |
19 | it "must have a :line_item if it's :in_use" do
20 | subject.status = 'in_use'
21 | is_expected.to validate_presence_of(:line_item)
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/spec/models/line_item_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe LineItem, type: :model do
4 | it { is_expected.to validate_presence_of :quantity }
5 | it { is_expected.to validate_numericality_of(:quantity).only_integer.is_greater_than(0) }
6 | it { is_expected.to validate_presence_of :payed_price }
7 | it { is_expected.to validate_numericality_of(:payed_price).is_greater_than(0) }
8 | it { is_expected.to validate_presence_of(:status).on(:update) }
9 | it { is_expected.to define_enum_for(:status).with_values(waiting_order: 1, preparing: 2, en_route: 3, delivered: 4) }
10 |
11 | it { is_expected.to belong_to :order }
12 | it { is_expected.to belong_to :product }
13 | it { is_expected.to have_many :licenses }
14 |
15 | it "receives :waiting_order status as default on creation" do
16 | subject = create(:line_item, status: nil)
17 | expect(subject.status).to eq 'waiting_order'
18 | end
19 |
20 | it "#total must be :payed_price multiplied by :quantity" do
21 | payed_price = 153.32
22 | quantity = 2
23 | subject = build(:line_item, payed_price: payed_price, quantity: quantity)
24 | expected_value = payed_price * quantity
25 | expect(subject.total).to eq expected_value
26 | end
27 |
28 | context "when #ship!" do
29 | it "sets line item with :processing status" do
30 | subject = create(:line_item)
31 | subject.ship!
32 | subject.reload
33 | expect(subject.status).to eq 'preparing'
34 | end
35 |
36 | it "#forwards to :productable #ship! method" do
37 | line_item = create(:line_item)
38 | productable = line_item.product.productable
39 | expect(productable).to receive(:ship!).with(line_item)
40 | line_item.ship!
41 | end
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/spec/models/product_category_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe ProductCategory, type: :model do
4 | it { is_expected.to belong_to :product }
5 | it { is_expected.to belong_to :category }
6 | end
7 |
--------------------------------------------------------------------------------
/spec/models/product_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe Product, type: :model do
4 | subject { build(:product) }
5 |
6 | it { is_expected.to validate_presence_of(:name) }
7 | it { is_expected.to validate_uniqueness_of(:name).case_insensitive }
8 | it { is_expected.to validate_presence_of(:description) }
9 | it { is_expected.to validate_presence_of(:price) }
10 | it { is_expected.to validate_numericality_of(:price).is_greater_than(0) }
11 | it { is_expected.to validate_presence_of(:image) }
12 | it { is_expected.to validate_presence_of(:status) }
13 | it { is_expected.to define_enum_for(:status).with_values({ available: 1, unavailable: 2 }) }
14 | it { is_expected.to validate_presence_of(:featured) }
15 |
16 | it { is_expected.to belong_to :productable }
17 | it { is_expected.to have_many(:product_categories).dependent(:destroy) }
18 | it { is_expected.to have_many(:categories).through(:product_categories) }
19 | it { is_expected.to have_many(:wish_items) }
20 | it { is_expected.to have_many(:line_items) }
21 |
22 | it_has_behavior_of "like searchable concern", :product, :name
23 | it_behaves_like "paginatable concern", :product
24 |
25 | it "creates as unfeatured by default" do
26 | subject.featured = nil
27 | subject.save(validate: false)
28 | expect(subject.featured).to be_falsey
29 | end
30 |
31 | it "#sells_count returns quantity product was sold" do
32 | order = create(:order)
33 | order.update(status: :finished)
34 | product = create(:product)
35 | create_list(:line_item, 2, quantity: 3, product: product, order: order)
36 | expect(product.sells_count).to eq 6
37 | end
38 | end
39 |
--------------------------------------------------------------------------------
/spec/models/system_requirement_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe SystemRequirement, type: :model do
4 | it { is_expected.to validate_presence_of(:name) }
5 | it { is_expected.to validate_uniqueness_of(:name).case_insensitive }
6 | it { is_expected.to validate_presence_of(:operational_system) }
7 | it { is_expected.to validate_presence_of(:storage) }
8 | it { is_expected.to validate_presence_of(:processor) }
9 | it { is_expected.to validate_presence_of(:memory) }
10 | it { is_expected.to validate_presence_of(:video_board) }
11 |
12 | it { is_expected.to have_many(:games).dependent(:restrict_with_error) }
13 |
14 | it_has_behavior_of "like searchable concern", :system_requirement, :name
15 | it_behaves_like "paginatable concern", :system_requirement
16 | end
17 |
--------------------------------------------------------------------------------
/spec/models/user_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe User, type: :model do
4 | it { is_expected.to have_many :wish_items }
5 | it { is_expected.to have_many :orders }
6 |
7 | it { is_expected.to validate_presence_of(:name) }
8 | it { is_expected.to validate_presence_of(:profile) }
9 | it { is_expected.to define_enum_for(:profile).with_values({ admin: 0, client: 1 }) }
10 |
11 | it_has_behavior_of "like searchable concern", :user, :name
12 | it_behaves_like "paginatable concern", :user
13 | end
14 |
--------------------------------------------------------------------------------
/spec/models/wish_item_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe WishItem, type: :model do
4 | subject { build(:wish_item) }
5 |
6 | it { is_expected.to belong_to :user }
7 | it { is_expected.to belong_to :product }
8 |
9 | it { is_expected.to validate_uniqueness_of(:product_id).scoped_to(:user_id) }
10 | end
11 |
--------------------------------------------------------------------------------
/spec/rails_helper.rb:
--------------------------------------------------------------------------------
1 | # This file is copied to spec/ when you run 'rails generate rspec:install'
2 | require 'spec_helper'
3 | ENV['RAILS_ENV'] ||= 'test'
4 | require File.expand_path('../config/environment', __dir__)
5 | # Prevent database truncation if the environment is production
6 | abort("The Rails environment is running in production mode!") if Rails.env.production?
7 | require 'rspec/rails'
8 |
9 | Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f }
10 | Dir[Rails.root.join('spec', 'shared_examples', '**', '*.rb')].each { |f| require f }
11 |
12 | begin
13 | ActiveRecord::Migration.maintain_test_schema!
14 | rescue ActiveRecord::PendingMigrationError => e
15 | puts e.to_s.strip
16 | exit 1
17 | end
18 |
19 | RSpec.configure do |config|
20 | config.use_transactional_fixtures = true
21 | config.infer_spec_type_from_file_location!
22 | config.filter_rails_from_backtrace!
23 | config.alias_it_behaves_like_to :it_has_behavior_of, 'has behavior of'
24 | end
25 |
--------------------------------------------------------------------------------
/spec/requests/admin/v1/categories/client_requests_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe "Admin V1 Categories as :client", type: :request do
4 | let(:user) { create(:user, profile: :client) }
5 |
6 | context "GET /categories" do
7 | let(:url) { "/admin/v1/categories" }
8 | let!(:categories) { create_list(:category, 5) }
9 |
10 | before(:each) { get url, headers: auth_header(user) }
11 |
12 | include_examples "forbidden access"
13 | end
14 |
15 | context "POST /categories" do
16 | let(:url) { "/admin/v1/categories" }
17 |
18 | before(:each) { post url, headers: auth_header(user) }
19 |
20 | include_examples "forbidden access"
21 | end
22 |
23 | context "GET /categories/:id" do
24 | let(:category) { create(:category) }
25 | let(:url) { "/admin/v1/categories/#{category.id}" }
26 |
27 | before(:each) { get url, headers: auth_header(user) }
28 |
29 | include_examples "forbidden access"
30 | end
31 |
32 | context "PATCH /categories/:id" do
33 | let(:category) { create(:category) }
34 | let(:url) { "/admin/v1/categories/#{category.id}" }
35 |
36 | before(:each) { patch url, headers: auth_header(user) }
37 |
38 | include_examples "forbidden access"
39 | end
40 |
41 | context "DELETE /categories/:id" do
42 | let!(:category) { create(:category) }
43 | let(:url) { "/admin/v1/categories/#{category.id}" }
44 |
45 | before(:each) { delete url, headers: auth_header(user) }
46 |
47 | include_examples "forbidden access"
48 | end
49 | end
50 |
--------------------------------------------------------------------------------
/spec/requests/admin/v1/categories/unautheticated_requests_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe "Admin V1 Categories without authentication", type: :request do
4 |
5 | context "GET /categories" do
6 | let(:url) { "/admin/v1/categories" }
7 | let!(:categories) { create_list(:category, 5) }
8 |
9 | before(:each) { get url }
10 |
11 | include_examples "unauthenticated access"
12 | end
13 |
14 | context "POST /categories" do
15 | let(:url) { "/admin/v1/categories" }
16 |
17 | before(:each) { post url }
18 |
19 | include_examples "unauthenticated access"
20 | end
21 |
22 | context "GET /categories/:id" do
23 | let(:category) { create(:category) }
24 | let(:url) { "/admin/v1/categories/#{category.id}" }
25 |
26 | before(:each) { get url }
27 |
28 | include_examples "unauthenticated access"
29 | end
30 |
31 | context "PATCH /categories/:id" do
32 | let(:category) { create(:category) }
33 | let(:url) { "/admin/v1/categories/#{category.id}" }
34 |
35 | before(:each) { patch url }
36 |
37 | include_examples "unauthenticated access"
38 | end
39 |
40 | context "DELETE /categories/:id" do
41 | let!(:category) { create(:category) }
42 | let(:url) { "/admin/v1/categories/#{category.id}" }
43 |
44 | before(:each) { delete url }
45 |
46 | include_examples "unauthenticated access"
47 | end
48 | end
49 |
--------------------------------------------------------------------------------
/spec/requests/admin/v1/coupons/client_requests_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe "Admin V1 Coupons as :client", type: :request do
4 | let(:user) { create(:user, profile: :client) }
5 |
6 | context "GET /coupons" do
7 | let(:url) { "/admin/v1/coupons" }
8 | let!(:coupons) { create_list(:coupon, 5) }
9 |
10 | before(:each) { get url, headers: auth_header(user) }
11 |
12 | include_examples "forbidden access"
13 | end
14 |
15 | context "POST /coupons" do
16 | let(:url) { "/admin/v1/coupons" }
17 |
18 | before(:each) { post url, headers: auth_header(user) }
19 |
20 | include_examples "forbidden access"
21 | end
22 |
23 | context "GET /coupons/:id" do
24 | let(:coupon) { create(:coupon) }
25 | let(:url) { "/admin/v1/coupons/#{coupon.id}" }
26 |
27 | before(:each) { get url, headers: auth_header(user) }
28 |
29 | include_examples "forbidden access"
30 | end
31 |
32 | context "PATCH /coupons/:id" do
33 | let(:coupon) { create(:coupon) }
34 | let(:url) { "/admin/v1/coupons/#{coupon.id}" }
35 |
36 | before(:each) { patch url, headers: auth_header(user) }
37 |
38 | include_examples "forbidden access"
39 | end
40 |
41 | context "DELETE /coupons/:id" do
42 | let!(:coupon) { create(:coupon) }
43 | let(:url) { "/admin/v1/coupons/#{coupon.id}" }
44 |
45 | before(:each) { delete url, headers: auth_header(user) }
46 |
47 | include_examples "forbidden access"
48 | end
49 | end
50 |
--------------------------------------------------------------------------------
/spec/requests/admin/v1/coupons/unautheticated_requests_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe "Admin V1 Coupons without authentication", type: :request do
4 |
5 | context "GET /coupons" do
6 | let(:url) { "/admin/v1/coupons" }
7 | let!(:coupons) { create_list(:coupon, 5) }
8 |
9 | before(:each) { get url }
10 |
11 | include_examples "unauthenticated access"
12 | end
13 |
14 | context "POST /coupons" do
15 | let(:url) { "/admin/v1/coupons" }
16 |
17 | before(:each) { post url }
18 |
19 | include_examples "unauthenticated access"
20 | end
21 |
22 | context "GET /coupons/:id" do
23 | let(:coupon) { create(:coupon) }
24 | let(:url) { "/admin/v1/coupons/#{coupon.id}" }
25 |
26 | before(:each) { get url }
27 |
28 | include_examples "unauthenticated access"
29 | end
30 |
31 | context "PATCH /coupons/:id" do
32 | let(:coupon) { create(:coupon) }
33 | let(:url) { "/admin/v1/coupons/#{coupon.id}" }
34 |
35 | before(:each) { patch url }
36 |
37 | include_examples "unauthenticated access"
38 | end
39 |
40 | context "DELETE /coupons/:id" do
41 | let!(:coupon) { create(:coupon) }
42 | let(:url) { "/admin/v1/coupons/#{coupon.id}" }
43 |
44 | before(:each) { delete url }
45 |
46 | include_examples "unauthenticated access"
47 | end
48 | end
49 |
--------------------------------------------------------------------------------
/spec/requests/admin/v1/dashboard/sales_ranges/admin_requests_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe "Admin V1 Dashboard Sales Ranges as :admin", type: :request do
4 | let(:user) { create(:user) }
5 |
6 | context "GET /dashboard/sales_ranges" do
7 | let(:url) { "/admin/v1/dashboard/sales_ranges" }
8 |
9 | context "when date range is less than one 1 month" do
10 | let(:params) { { min_date: 20.days.ago.strftime("%Y-%m-%d"), max_date: Date.current.strftime("%Y-%m-%d") } }
11 |
12 | let(:product) { create(:product) }
13 |
14 | let!(:sales_line_items) do
15 | 20.downto(1).map do |num|
16 | order = create(:order, created_at: num.days.ago)
17 | order.update_column(:status, :finished)
18 | create(:line_item, order: order, product: product, payed_price: 200, quantity: num)
19 | end
20 | end
21 |
22 | it "returns products in a daily basis" do
23 | get url, headers: auth_header(user), params: params
24 | expected_result = sales_line_items.map do |line_item|
25 | day = line_item.order.created_at.strftime("%Y-%m-%d")
26 | total_sold = line_item.payed_price * line_item.quantity
27 | { "date" => day, "total_sold" => total_sold.to_f }
28 | end
29 | expect(body_json['sales_ranges']).to eq expected_result
30 | end
31 |
32 | it "returns :ok status" do
33 | get url, headers: auth_header(user), params: params
34 | expect(response).to have_http_status(:ok)
35 | end
36 | end
37 |
38 | context "when date range is more than one 1 month" do
39 | let(:params) { { min_date: 5.months.ago.strftime("%Y-%m-%d"), max_date: Date.current.strftime("%Y-%m-%d") } }
40 |
41 | let(:product) { create(:product) }
42 |
43 | let!(:sales_line_items) do
44 | 5.downto(1).map do |num|
45 | order = create(:order, created_at: num.months.ago)
46 | order.update_column(:status, :finished)
47 | create(:line_item, order: order, product: product, payed_price: 200, quantity: num)
48 | end
49 | end
50 |
51 | it "returns products in a monthly basis" do
52 | get url, headers: auth_header(user), params: params
53 | expected_result = sales_line_items.map do |line_item|
54 | month = line_item.order.created_at.strftime("%Y-%m")
55 | total_sold = line_item.payed_price * line_item.quantity
56 | { "date" => month, "total_sold" => total_sold.to_f }
57 | end
58 | expect(body_json['sales_ranges']).to eq expected_result
59 | end
60 |
61 | it "returns :ok status" do
62 | get url, headers: auth_header(user), params: params
63 | expect(response).to have_http_status(:ok)
64 | end
65 | end
66 | end
67 | end
--------------------------------------------------------------------------------
/spec/requests/admin/v1/dashboard/sales_ranges/client_requests_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe "Admin V1 Dashboard Sales Ranges as :client", type: :request do
4 | let(:user) { create(:user, profile: :client) }
5 |
6 | context "GET /dashboard/sales_ranges" do
7 | let(:url) { "/admin/v1/dashboard/sales_ranges" }
8 |
9 | before(:each) { get url, headers: auth_header(user) }
10 |
11 | include_examples "forbidden access"
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/spec/requests/admin/v1/dashboard/sales_ranges/unautheticated_requests_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe "Admin V1 Dashboard Sales Ranges without authentication", type: :request do
4 |
5 | context "GET /dashboard/sales_ranges" do
6 | let(:url) { "/admin/v1/dashboard/sales_ranges" }
7 |
8 | before(:each) { get url }
9 |
10 | include_examples "unauthenticated access"
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/spec/requests/admin/v1/dashboard/summaries/admin_requests_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe "Admin V1 Dashboard Summaries as :admin", type: :request do
4 | let(:user) { create(:user) }
5 |
6 | context "GET /dashboard/summaries" do
7 | let(:url) { "/admin/v1/dashboard/summaries" }
8 | let(:params) { { min_date: 3.days.ago.strftime("%Y-%m-%d"), max_date: Date.current.strftime("%Y-%m-%d") } }
9 | let!(:users) { create_list(:user, 5, created_at: 2.days.ago) }
10 | let!(:users_out_of_range) { create_list(:user, 5, created_at: 4.days.ago) }
11 | let!(:products) { create_list(:product, 5, created_at: 2.days.ago) }
12 | let!(:products_out_of_range) { create_list(:product, 5, created_at: 4.days.ago) }
13 | let!(:orders) do
14 | create_list(:order, 5, user: user, created_at: 2.days.ago, total_amount: 54.15).map do |order|
15 | order.update_column(:status, :finished)
16 | order
17 | end
18 | end
19 | let!(:orders_out_of_range) do
20 | create_list(:order, 5, user: user, created_at: 4.days.ago, total_amount: 54.15).map do |order|
21 | order.update_column(:status, :finished)
22 | order
23 | end
24 | end
25 |
26 | it "returns right summary of data" do
27 | get url, headers: auth_header(user), params: params
28 | expected_profit = orders.sum(&:total_amount)
29 | expected_result = {
30 | users: users.size + 1, products: products.size, orders: orders.size, profit: expected_profit
31 | }.as_json
32 | expect(body_json['summary']).to eq expected_result
33 | end
34 |
35 | it "returns :ok status" do
36 | get url, headers: auth_header(user), params: params
37 | expect(response).to have_http_status(:ok)
38 | end
39 | end
40 | end
41 |
--------------------------------------------------------------------------------
/spec/requests/admin/v1/dashboard/summaries/client_requests_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe "Admin V1 Dashboard Summaries as :client", type: :request do
4 | let(:user) { create(:user, profile: :client) }
5 |
6 | context "GET /dashboard/summaries" do
7 | let(:url) { "/admin/v1/dashboard/summaries" }
8 |
9 | before(:each) { get url, headers: auth_header(user) }
10 |
11 | include_examples "forbidden access"
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/spec/requests/admin/v1/dashboard/summaries/unautheticated_requests_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe "Admin V1 Dashboard Summaries without authentication", type: :request do
4 |
5 | context "GET /dashboard/summaries" do
6 | let(:url) { "/admin/v1/dashboard/summaries" }
7 |
8 | before(:each) { get url }
9 |
10 | include_examples "unauthenticated access"
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/spec/requests/admin/v1/dashboard/top_five_products/admin_requests_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe "Admin V1 Dashboard Top Five Products as :admin", type: :request do
4 | let(:user) { create(:user) }
5 |
6 | context "GET /dashboard/top_five_products" do
7 | let(:url) { "/admin/v1/dashboard/top_five_products" }
8 | let(:params) { { min_date: 5.days.ago.strftime("%Y-%m-%d"), max_date: Date.current.strftime("%Y-%m-%d") } }
9 |
10 | let(:top_five_products) { create_list(:product, 5) }
11 | let(:less_sold_products) { create_list(:product, 5) }
12 | let(:order) do
13 | order = create(:order, created_at: 4.days.ago)
14 | order.update_column(:status, :finished)
15 | order
16 | end
17 | let!(:top_five_line_itens) do
18 | top_five_products.map.with_index do |product, index|
19 | create(:line_item, payed_price: 200, quantity: (index + 1), order: order, product: product)
20 | end
21 | end
22 | let(:out_of_date_order) do
23 | order = create(:order, created_at: 8.days.ago)
24 | order.update_column(:status, :finished)
25 | order
26 | end
27 | let!(:out_of_date_line_items) do
28 | less_sold_products.map.with_index do |product, index|
29 | create(:line_item, payed_price: 2000, quantity: (index + 1), order: out_of_date_order, product: product)
30 | end
31 | end
32 |
33 |
34 | it "returns right top five products" do
35 | get url, headers: auth_header(user), params: params
36 | expected_result = top_five_line_itens.reverse.map do |line_item|
37 | total_sold = line_item.quantity * line_item.payed_price
38 | product = line_item.product
39 | {
40 | 'product' => product.name, 'image' => rails_blob_url(product.image, host: "localhost", port: 3000),
41 | 'quantity' => line_item.quantity, 'total_sold' => total_sold.to_f
42 | }
43 | end
44 | expect(body_json['top_five_products']).to eq expected_result
45 | end
46 |
47 | it "returns :ok status" do
48 | get url, headers: auth_header(user), params: params
49 | expect(response).to have_http_status(:ok)
50 | end
51 | end
52 | end
53 |
--------------------------------------------------------------------------------
/spec/requests/admin/v1/dashboard/top_five_products/client_requests_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe "Admin V1 Dashboard Top Five Products as :client", type: :request do
4 | let(:user) { create(:user, profile: :client) }
5 |
6 | context "GET /dashboard/top_five_products" do
7 | let(:url) { "/admin/v1/dashboard/top_five_products" }
8 |
9 | before(:each) { get url, headers: auth_header(user) }
10 |
11 | include_examples "forbidden access"
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/spec/requests/admin/v1/dashboard/top_five_products/unautheticated_requests_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe "Admin V1 Dashboard Top Five Products without authentication", type: :request do
4 |
5 | context "GET /dashboard/top_five_products" do
6 | let(:url) { "/admin/v1/dashboard/top_five_products" }
7 |
8 | before(:each) { get url }
9 |
10 | include_examples "unauthenticated access"
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/spec/requests/admin/v1/home_spec.rb:
--------------------------------------------------------------------------------
1 | require "rails_helper"
2 |
3 | describe "Home", type: :request do
4 | let(:user) { create(:user) }
5 |
6 | it "tests home" do
7 | get '/admin/v1/home', headers: auth_header(user)
8 | expect(body_json).to eq({ 'message' => 'Uhul!' })
9 | end
10 |
11 | it "tests home" do
12 | get '/admin/v1/home', headers: auth_header(user)
13 | expect(response).to have_http_status(:ok)
14 | end
15 | end
--------------------------------------------------------------------------------
/spec/requests/admin/v1/licenses/client_requests_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe "Admin V1 Licenses as :client", type: :request do
4 | let(:user) { create(:user, profile: :client) }
5 | let(:game) { create(:game) }
6 |
7 | context "GET /games/:game_id/licenses" do
8 | let(:url) { "/admin/v1/games/#{game.id}/licenses" }
9 | let!(:licenses) { create_list(:license, 5, game: game) }
10 |
11 | before(:each) { get url, headers: auth_header(user) }
12 |
13 | include_examples "forbidden access"
14 | end
15 |
16 | context "POST /games/:game_id/licenses" do
17 | let(:url) { "/admin/v1/games/#{game.id}/licenses" }
18 |
19 | before(:each) { post url, headers: auth_header(user) }
20 |
21 | include_examples "forbidden access"
22 | end
23 |
24 | context "GET /licenses/:id" do
25 | let(:license) { create(:license) }
26 | let(:url) { "/admin/v1/licenses/#{license.id}" }
27 |
28 | before(:each) { get url, headers: auth_header(user) }
29 |
30 | include_examples "forbidden access"
31 | end
32 |
33 | context "PATCH /licenses/:id" do
34 | let(:license) { create(:license) }
35 | let(:url) { "/admin/v1/licenses/#{license.id}" }
36 |
37 | before(:each) { patch url, headers: auth_header(user) }
38 |
39 | include_examples "forbidden access"
40 | end
41 |
42 | context "DELETE /licenses/:id" do
43 | let!(:license) { create(:license) }
44 | let(:url) { "/admin/v1/licenses/#{license.id}" }
45 |
46 | before(:each) { delete url, headers: auth_header(user) }
47 |
48 | include_examples "forbidden access"
49 | end
50 | end
51 |
--------------------------------------------------------------------------------
/spec/requests/admin/v1/licenses/unauthenticated_requests_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe "Admin V1 Licenses without authentication", type: :request do
4 | let(:game) { create(:game) }
5 |
6 | context "GET /games/:game_id/licenses" do
7 | let(:url) { "/admin/v1/games/#{game.id}/licenses" }
8 | let!(:licenses) { create_list(:license, 5) }
9 |
10 | before(:each) { get url }
11 |
12 | include_examples "unauthenticated access"
13 | end
14 |
15 | context "POST /games/:game_id/licenses" do
16 | let(:url) { "/admin/v1/games/#{game.id}/licenses" }
17 |
18 | before(:each) { post url }
19 |
20 | include_examples "unauthenticated access"
21 | end
22 |
23 | context "GET /licenses/:id" do
24 | let(:license) { create(:license) }
25 | let(:url) { "/admin/v1/licenses/#{license.id}" }
26 |
27 | before(:each) { get url }
28 |
29 | include_examples "unauthenticated access"
30 | end
31 |
32 | context "PATCH /licenses/:id" do
33 | let(:license) { create(:license) }
34 | let(:url) { "/admin/v1/licenses/#{license.id}" }
35 |
36 | before(:each) { patch url }
37 |
38 | include_examples "unauthenticated access"
39 | end
40 |
41 | context "DELETE /licenses/:id" do
42 | let!(:license) { create(:license) }
43 | let(:url) { "/admin/v1/licenses/#{license.id}" }
44 |
45 | before(:each) { delete url }
46 |
47 | include_examples "unauthenticated access"
48 | end
49 | end
50 |
--------------------------------------------------------------------------------
/spec/requests/admin/v1/orders/client_requests_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe "Admin V1 Orders as :client", type: :request do
4 | let(:user) { create(:user, profile: :client) }
5 |
6 | context "GET /orders" do
7 | let(:url) { "/admin/v1/orders" }
8 | let!(:orders) { create_list(:order, 5) }
9 |
10 | before(:each) { get url, headers: auth_header(user) }
11 |
12 | include_examples "forbidden access"
13 | end
14 |
15 | context "GET /orders/:id" do
16 | let(:order) { create(:order) }
17 | let(:url) { "/admin/v1/orders/#{order.id}" }
18 |
19 | before(:each) { get url, headers: auth_header(user) }
20 |
21 | include_examples "forbidden access"
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/spec/requests/admin/v1/orders/unautheticated_requests_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe "Admin V1 Orders without authentication", type: :request do
4 | context "GET /orders" do
5 | let(:url) { "/admin/v1/orders" }
6 | let!(:orders) { create_list(:order, 5) }
7 |
8 | before(:each) { get url }
9 |
10 | include_examples "unauthenticated access"
11 | end
12 |
13 | context "GET /orders/:id" do
14 | let(:order) { create(:order) }
15 | let(:url) { "/admin/v1/orders/#{order.id}" }
16 |
17 | before(:each) { get url }
18 |
19 | include_examples "unauthenticated access"
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/spec/requests/admin/v1/products/client_requests_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe "Admin V1 Products as :client", type: :request do
4 | let(:user) { create(:user, profile: :client) }
5 |
6 | context "GET /products" do
7 | let(:url) { "/admin/v1/products" }
8 | let!(:products) { create_list(:product, 5) }
9 |
10 | before(:each) { get url, headers: auth_header(user) }
11 |
12 | include_examples "forbidden access"
13 | end
14 |
15 | context "POST /products" do
16 | let(:url) { "/admin/v1/products" }
17 |
18 | before(:each) { post url, headers: auth_header(user) }
19 |
20 | include_examples "forbidden access"
21 | end
22 |
23 | context "GET /products/:id" do
24 | let(:product) { create(:product) }
25 | let(:url) { "/admin/v1/products/#{product.id}" }
26 |
27 | before(:each) { get url, headers: auth_header(user) }
28 |
29 | include_examples "forbidden access"
30 | end
31 |
32 | context "PATCH /products/:id" do
33 | let(:product) { create(:product) }
34 | let(:url) { "/admin/v1/products/#{product.id}" }
35 |
36 | before(:each) { patch url, headers: auth_header(user) }
37 |
38 | include_examples "forbidden access"
39 | end
40 |
41 | context "DELETE /products/:id" do
42 | let!(:product) { create(:product) }
43 | let(:url) { "/admin/v1/products/#{product.id}" }
44 |
45 | before(:each) { delete url, headers: auth_header(user) }
46 |
47 | include_examples "forbidden access"
48 | end
49 | end
50 |
--------------------------------------------------------------------------------
/spec/requests/admin/v1/products/unautheticated_requests_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe "Admin V1 Product without authentication", type: :request do
4 |
5 | context "GET /products" do
6 | let(:url) { "/admin/v1/products" }
7 | let!(:products) { create_list(:product, 5) }
8 |
9 | before(:each) { get url }
10 |
11 | include_examples "unauthenticated access"
12 | end
13 |
14 | context "POST /products" do
15 | let(:url) { "/admin/v1/products" }
16 |
17 | before(:each) { post url }
18 |
19 | include_examples "unauthenticated access"
20 | end
21 |
22 | context "GET /products/:id" do
23 | let(:product) { create(:product) }
24 | let(:url) { "/admin/v1/products/#{product.id}" }
25 |
26 | before(:each) { get url }
27 |
28 | include_examples "unauthenticated access"
29 | end
30 |
31 | context "PATCH /products/:id" do
32 | let(:product) { create(:product) }
33 | let(:url) { "/admin/v1/products/#{product.id}" }
34 |
35 | before(:each) { patch url }
36 |
37 | include_examples "unauthenticated access"
38 | end
39 |
40 | context "DELETE /products/:id" do
41 | let!(:product) { create(:product) }
42 | let(:url) { "/admin/v1/products/#{product.id}" }
43 |
44 | before(:each) { delete url }
45 |
46 | include_examples "unauthenticated access"
47 | end
48 | end
49 |
--------------------------------------------------------------------------------
/spec/requests/admin/v1/system_requirements/client_requests_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe "Admin V1 System Requirements as :client", type: :request do
4 | let(:user) { create(:user, profile: :client) }
5 |
6 | context "GET /system_requirements" do
7 | let(:url) { "/admin/v1/system_requirements" }
8 | let!(:system_requirements) { create_list(:system_requirement, 5) }
9 |
10 | before(:each) { get url, headers: auth_header(user) }
11 |
12 | include_examples "forbidden access"
13 | end
14 |
15 | context "POST /system_requirements" do
16 | let(:url) { "/admin/v1/system_requirements" }
17 |
18 | before(:each) { post url, headers: auth_header(user) }
19 |
20 | include_examples "forbidden access"
21 | end
22 |
23 | context "GET /system_requirements/:id" do
24 | let(:system_requirement) { create(:system_requirement) }
25 | let(:url) { "/admin/v1/system_requirements/#{system_requirement.id}" }
26 |
27 | before(:each) { get url, headers: auth_header(user) }
28 |
29 | include_examples "forbidden access"
30 | end
31 |
32 | context "PATCH /system_requirements/:id" do
33 | let(:system_requirement) { create(:system_requirement) }
34 | let(:url) { "/admin/v1/system_requirements/#{system_requirement.id}" }
35 |
36 | before(:each) { patch url, headers: auth_header(user) }
37 |
38 | include_examples "forbidden access"
39 | end
40 |
41 | context "DELETE /system_requirements/:id" do
42 | let!(:system_requirement) { create(:system_requirement) }
43 | let(:url) { "/admin/v1/system_requirements/#{system_requirement.id}" }
44 |
45 | before(:each) { delete url, headers: auth_header(user) }
46 |
47 | include_examples "forbidden access"
48 | end
49 | end
50 |
--------------------------------------------------------------------------------
/spec/requests/admin/v1/system_requirements/unautheticated_requests_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe "Admin V1 System Requirements without authentication", type: :request do
4 |
5 | context "GET /system_requirements" do
6 | let(:url) { "/admin/v1/system_requirements" }
7 | let!(:system_requirements) { create_list(:system_requirement, 5) }
8 |
9 | before(:each) { get url }
10 |
11 | include_examples "unauthenticated access"
12 | end
13 |
14 | context "POST /system_requirements" do
15 | let(:url) { "/admin/v1/system_requirements" }
16 |
17 | before(:each) { post url }
18 |
19 | include_examples "unauthenticated access"
20 | end
21 |
22 | context "GET /system_requirements/:id" do
23 | let(:system_requirement) { create(:system_requirement) }
24 | let(:url) { "/admin/v1/system_requirements/#{system_requirement.id}" }
25 |
26 | before(:each) { get url }
27 |
28 | include_examples "unauthenticated access"
29 | end
30 |
31 | context "PATCH /system_requirements/:id" do
32 | let(:system_requirement) { create(:system_requirement) }
33 | let(:url) { "/admin/v1/system_requirements/#{system_requirement.id}" }
34 |
35 | before(:each) { patch url }
36 |
37 | include_examples "unauthenticated access"
38 | end
39 |
40 | context "DELETE /system_requirements/:id" do
41 | let!(:system_requirement) { create(:system_requirement) }
42 | let(:url) { "/admin/v1/system_requirements/#{system_requirement.id}" }
43 |
44 | before(:each) { delete url }
45 |
46 | include_examples "unauthenticated access"
47 | end
48 | end
49 |
--------------------------------------------------------------------------------
/spec/requests/admin/v1/users/client_requests_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe "Admin V1 Users as :client", type: :request do
4 | let(:login_user) { create(:user, profile: :client) }
5 |
6 | context "GET /users" do
7 | let(:url) { "/admin/v1/users" }
8 | let!(:users) { create_list(:user, 5) }
9 |
10 | before(:each) { get url, headers: auth_header(login_user) }
11 |
12 | include_examples "forbidden access"
13 | end
14 |
15 | context "POST /users" do
16 | let(:url) { "/admin/v1/users" }
17 |
18 | before(:each) { post url, headers: auth_header(login_user) }
19 |
20 | include_examples "forbidden access"
21 | end
22 |
23 | context "GET /users/:id" do
24 | let(:user) { create(:user) }
25 | let(:url) { "/admin/v1/users/#{user.id}" }
26 |
27 | before(:each) { get url, headers: auth_header(login_user) }
28 |
29 | include_examples "forbidden access"
30 | end
31 |
32 | context "PATCH /users/:id" do
33 | let(:user) { create(:user) }
34 | let(:url) { "/admin/v1/users/#{user.id}" }
35 |
36 | before(:each) { patch url, headers: auth_header(login_user) }
37 |
38 | include_examples "forbidden access"
39 | end
40 |
41 | context "DELETE /users/:id" do
42 | let!(:user) { create(:user) }
43 | let(:url) { "/admin/v1/users/#{user.id}" }
44 |
45 | before(:each) { delete url, headers: auth_header(login_user) }
46 |
47 | include_examples "forbidden access"
48 | end
49 | end
50 |
--------------------------------------------------------------------------------
/spec/requests/admin/v1/users/unautheticated_requests_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe "Admin V1 Users without authentication", type: :request do
4 |
5 | context "GET /users" do
6 | let(:url) { "/admin/v1/users" }
7 | let!(:users) { create_list(:user, 5) }
8 |
9 | before(:each) { get url }
10 |
11 | include_examples "unauthenticated access"
12 | end
13 |
14 | context "POST /users" do
15 | let(:url) { "/admin/v1/users" }
16 |
17 | before(:each) { post url }
18 |
19 | include_examples "unauthenticated access"
20 | end
21 |
22 | context "GET /users/:id" do
23 | let(:user) { create(:user) }
24 | let(:url) { "/admin/v1/users/#{user.id}" }
25 |
26 | before(:each) { get url }
27 |
28 | include_examples "unauthenticated access"
29 | end
30 |
31 | context "PATCH /users/:id" do
32 | let(:user) { create(:user) }
33 | let(:url) { "/admin/v1/users/#{user.id}" }
34 |
35 | before(:each) { patch url }
36 |
37 | include_examples "unauthenticated access"
38 | end
39 |
40 | context "DELETE /users/:id" do
41 | let!(:user) { create(:user) }
42 | let(:url) { "/admin/v1/users/#{user.id}" }
43 |
44 | before(:each) { delete url }
45 |
46 | include_examples "unauthenticated access"
47 | end
48 | end
49 |
--------------------------------------------------------------------------------
/spec/requests/auth/v1/sign_in_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe "Auth V1 Sign in", type: :request do
4 | context "as :admin" do
5 | let!(:user) { create(:user, email: "admin@test.com", password: "123456") }
6 |
7 | include_examples 'sign in', 'admin@test.com', '123456'
8 | end
9 |
10 | context "as :client" do
11 | let!(:user) { create(:user, profile: :client, email: "client@test.com", password: "123456") }
12 |
13 | include_examples 'sign in', 'client@test.com', '123456'
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/spec/requests/auth/v1/sign_out_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe "Auth V1 Sign out", type: :request do
4 | let(:url) { '/auth/v1/user/sign_out' }
5 | let!(:user) { create(:user) }
6 |
7 | it "removes a token from User" do
8 | user_headers = auth_header(user)
9 | user_token = user_headers['client']
10 | delete url, headers: user_headers
11 | user.reload
12 | expect(user.tokens.keys).to_not include(user_token)
13 | end
14 |
15 | it "returns :ok status" do
16 | delete url, headers: auth_header(user)
17 | expect(response).to have_http_status(:ok)
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/spec/requests/auth/v1/sign_up_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe "Auth V1 Sign up", type: :request do
4 | let(:url) { '/auth/v1/user' }
5 |
6 | context "with valid params" do
7 | let(:user_params) { attributes_for(:user, profile: nil) }
8 |
9 | it "adds new User" do
10 | expect {
11 | post url, params: user_params
12 | }.to change(User, :count).by(1)
13 | end
14 |
15 | it "add User as :client" do
16 | post url, params: user_params
17 | expect(User.last.profile).to eq 'client'
18 | end
19 |
20 | it "returns :ok status" do
21 | post url, params: user_params
22 | expect(response).to have_http_status(:ok)
23 | end
24 | end
25 |
26 | context "with invalid params" do
27 | let(:user_invalid_params) { attributes_for(:user, email: nil) }
28 |
29 | it "does not add a new User" do
30 | expect {
31 | post url, params: user_invalid_params
32 | }.to_not change(User, :count)
33 | end
34 |
35 | it "return :unprocessable_entity status" do
36 | post url, params: user_invalid_params
37 | expect(response).to have_http_status(:unprocessable_entity)
38 | end
39 | end
40 | end
41 |
--------------------------------------------------------------------------------
/spec/requests/juno/v1/payment_confirmations/authenticated_requests_spec.rb:
--------------------------------------------------------------------------------
1 | require "rails_helper"
2 |
3 | RSpec.describe "Juno V1 Payment Confirmations without authentication", type: :request do
4 | context "POST /payment_confirmations" do
5 | let(:token) { Rails.application.credentials.token[:auth] }
6 | let(:url) { "/juno/v1/payment_confirmations?token=#{token}" }
7 | let!(:order) { create(:order, status: :waiting_payment, payment_type: :billet) }
8 | let!(:juno_charges) { create(:juno_charge, order: order) }
9 |
10 | context "when 'chargeCode' param is present" do
11 | let(:params) do
12 | { 'paymentToken' => SecureRandom.hex, 'chargeReference' => '', 'chargeCode' => juno_charges.code }
13 | end
14 |
15 | it "sets order with :payment_accepted status" do
16 | post url, headers: unauthenticated_header, params: params.to_json
17 | order.reload
18 | expect(order.status).to eq 'payment_accepted'
19 | end
20 |
21 | it "returns :ok status" do
22 | post url, headers: unauthenticated_header, params: params.to_json
23 | expect(response).to have_http_status(:ok)
24 | end
25 | end
26 |
27 | context "when 'chargeCode' param does not exist" do
28 | let(:params) do
29 | { 'paymentToken' => SecureRandom.hex, 'chargeReference' => '', 'chargeCode' => 'some_random_code' }
30 | end
31 |
32 | it "keep order with same status" do
33 | post url, headers: unauthenticated_header, params: params.to_json
34 | old_status = order.status
35 | order.reload
36 | expect(order.status).to eq old_status
37 | end
38 |
39 | it "returns :ok status" do
40 | post url, headers: unauthenticated_header, params: params.to_json
41 | expect(response).to have_http_status(:ok)
42 | end
43 | end
44 |
45 | context "when 'chargeCode' param is not present" do
46 | let(:params) { { 'someOtherParam' => 'some_param_value' } }
47 |
48 | it "keep order with same status" do
49 | post url, headers: unauthenticated_header, params: params.to_json
50 | old_status = order.status
51 | order.reload
52 | expect(order.status).to eq old_status
53 | end
54 |
55 | it "returns :ok status" do
56 | post url, headers: unauthenticated_header, params: params.to_json
57 | expect(response).to have_http_status(:ok)
58 | end
59 | end
60 | end
61 | end
--------------------------------------------------------------------------------
/spec/requests/juno/v1/payment_confirmations/unauthenticated_requests_spec.rb:
--------------------------------------------------------------------------------
1 | require "rails_helper"
2 |
3 | RSpec.describe "Juno V1 Payment Confirmations", type: :request do
4 | context "POST /payment_confirmations" do
5 | let(:url) { "/juno/v1/payment_confirmations" }
6 | let!(:order) { create(:order, status: :waiting_payment, payment_type: :billet) }
7 | let!(:juno_charges) { create(:juno_charge, order: order) }
8 |
9 | before(:each) { post url }
10 |
11 | include_examples "unauthenticated access"
12 | end
13 | end
--------------------------------------------------------------------------------
/spec/requests/storefront/v1/categories/unathenticated_requests_spec.rb:
--------------------------------------------------------------------------------
1 | require "rails_helper"
2 |
3 | RSpec.describe "Storefront V1 Home", type: :request do
4 | context "GET /categories" do
5 | let(:url) { "/storefront/v1/categories" }
6 | let!(:categories) { create_list(:category, 15) }
7 |
8 | it "returns all Categories" do
9 | get url, headers: unauthenticated_header
10 | expect(body_json['categories'].count).to eq 15
11 | end
12 |
13 | it "returns Categories ordered by name" do
14 | get url, headers: unauthenticated_header
15 | expected_categories = categories.sort { |a, b| a[:name] <=> b[:name] }.as_json(only: %i(id name))
16 | expect(body_json['categories']).to contain_exactly *expected_categories
17 | end
18 |
19 | it "returns success status" do
20 | get url, headers: unauthenticated_header
21 | expect(response).to have_http_status(:ok)
22 | end
23 | end
24 | end
--------------------------------------------------------------------------------
/spec/requests/storefront/v1/checkouts/authenticated_request_spec.rb:
--------------------------------------------------------------------------------
1 | RSpec.describe "Storefront V1 Checkout as authenticated user", type: :request do
2 | let(:user) { create(:user, [:admin, :client].sample) }
3 |
4 | context "POST /checkouts" do
5 | let(:url) { "/storefront/v1/checkouts" }
6 | let!(:products) { create_list(:product, 3) }
7 |
8 | context "with valid params" do
9 | let!(:coupon) { create(:coupon) }
10 | let(:params) do
11 | {
12 | checkout: {
13 | payment_type: :credit_card, installments: 2,
14 | document: '03.000.050/0001-67', card_hash: "123456", address: attributes_for(:address),
15 | items: [
16 | { quantity: 2, product_id: products.first.id },
17 | { quantity: 3, product_id: products.second.id }
18 | ]
19 | }
20 | }.to_json
21 | end
22 |
23 | it 'creates a new Order' do
24 | expect do
25 | post url, headers: auth_header, params: params
26 | end.to change(Order, :count).by(1)
27 | end
28 |
29 | it 'creates associated Line Items' do
30 | expect do
31 | post url, headers: auth_header, params: params
32 | end.to change(LineItem, :count).by(2)
33 | end
34 |
35 | it 'returns created Order with associated Line Itens and Coupon' do
36 | post url, headers: auth_header, params: params
37 | order = Order.last
38 | expected_order = order.as_json(only: %i(id payment_type installments))
39 | expected_order.merge!('subtotal' => order.subtotal.to_f, 'total_amount' => order.total_amount.to_f)
40 | expect(body_json['order']).to eq expected_order
41 | end
42 |
43 | it 'returns success status' do
44 | post url, headers: auth_header, params: params
45 | expect(response).to have_http_status(:ok)
46 | end
47 | end
48 |
49 | context "with invalid params" do
50 | let(:invalid_params) do
51 | {
52 | checkout: {
53 | installments: 2, document: '03.000.050/0001-67',
54 | items: [
55 | { quantity: 2, product_id: products.first.id },
56 | { quantity: 3, product_id: products.second.id }
57 | ]
58 | }
59 | }.to_json
60 | end
61 |
62 | it 'does not create a Order' do
63 | expect do
64 | post url, headers: auth_header, params: invalid_params
65 | end.to_not change(Order, :count)
66 | end
67 |
68 | it 'does not create any Line Items' do
69 | expect do
70 | post url, headers: auth_header, params: invalid_params
71 | end.to_not change(LineItem, :count)
72 | end
73 |
74 | it 'returns error message' do
75 | post url, headers: auth_header, params: invalid_params
76 | expect(body_json['errors']['fields']).to have_key('payment_type')
77 | end
78 |
79 | it 'returns unprocessable_entity status' do
80 | post url, headers: auth_header, params: invalid_params
81 | expect(response).to have_http_status(:unprocessable_entity)
82 | end
83 | end
84 | end
85 | end
--------------------------------------------------------------------------------
/spec/requests/storefront/v1/checkouts/unautheticated_requests_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe "Storefront V1 Checkouts without authentication", type: :request do
4 |
5 | context "POST /checkouts" do
6 | let(:url) { "/storefront/v1/checkouts" }
7 |
8 | before(:each) { post url }
9 |
10 | include_examples "unauthenticated access"
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/spec/requests/storefront/v1/coupon_validations/authenticated_requests_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe "Storefront V1 Coupon Validation as authenticated user", type: :request do
4 | let(:user) { create(:user, [:admin, :client].sample) }
5 |
6 | context "POST /coupons/:coupon_code/validations" do
7 | context "with valid coupon" do
8 | let(:coupon) { create(:coupon) }
9 | let(:url) { "/storefront/v1/coupons/#{coupon.code}/validations" }
10 |
11 | it 'returns success status' do
12 | post url, headers: auth_header(user)
13 | expect(response).to have_http_status(:ok)
14 | end
15 |
16 | it 'returns valid Coupon' do
17 | post url, headers: auth_header(user)
18 | expected_coupon = coupon.as_json(only: %i(id code discount_value))
19 | expect(body_json['coupon']).to eq expected_coupon
20 | end
21 | end
22 |
23 | context "with invalid coupon" do
24 | let(:coupon) { create(:coupon, status: :inactive) }
25 | let(:url) { "/storefront/v1/coupons/#{coupon.code}/validations" }
26 |
27 | it 'returns unprocessable_entity status' do
28 | post url, headers: auth_header(user)
29 | expect(response).to have_http_status(:unprocessable_entity)
30 | end
31 |
32 | it 'returns valid Coupon' do
33 | post url, headers: auth_header(user)
34 | failure_message = I18n.t('storefront/v1/coupon_validations.create.failure')
35 | expect(body_json['errors']['message']).to eq failure_message
36 | end
37 | end
38 |
39 | context "when coupon does not exist" do
40 | let(:url) { "/storefront/v1/coupons/aaa/validations" }
41 |
42 | it 'returns unprocessable_entity status' do
43 | post url, headers: auth_header(user)
44 | expect(response).to have_http_status(:unprocessable_entity)
45 | end
46 |
47 | it 'returns valid Coupon' do
48 | post url, headers: auth_header(user)
49 | failure_message = I18n.t('storefront/v1/coupon_validations.create.failure')
50 | expect(body_json['errors']['message']).to eq failure_message
51 | end
52 | end
53 | end
54 | end
55 |
--------------------------------------------------------------------------------
/spec/requests/storefront/v1/coupon_validations/unautheticated_requests_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe "Storefront V1 Coupon Validation without authentication", type: :request do
4 |
5 | context "POST /coupons/:coupon_code/validations" do
6 | let(:coupon) { create(:coupon) }
7 | let(:url) { "/storefront/v1/coupons/#{coupon.code}/validations" }
8 |
9 | before(:each) { post url }
10 |
11 | include_examples "unauthenticated access"
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/spec/requests/storefront/v1/games/authenticated_requests_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe "Storefront V1 Games as authenticated user", type: :request do
4 | let(:user) { create(:user) }
5 |
6 | context "GET /games" do
7 | let(:url) { "/storefront/v1/games" }
8 | let!(:user_games) { create_list(:product, 3) }
9 | let!(:order) { create(:order, user: user) }
10 | let!(:line_items) do
11 | 0.upto(2).map { |index| create(:line_item, order: order, product: user_games[index], quantity: 1) }
12 | end
13 | let!(:licenses) do
14 | line_items.map { |line_item| create_list(:license, line_item.quantity, line_item: line_item) }
15 | end
16 | let!(:non_user_order) { create(:order) }
17 | let!(:non_user_line_items) { create_list(:line_item, 4, order: non_user_order, product: user_games.first) }
18 | let!(:non_user_licenses) do
19 | non_user_line_items.map { |line_item| create_list(:license, line_item.quantity, line_item: line_item) }
20 | end
21 |
22 | it "returns all user games" do
23 | get url, headers: auth_header(user)
24 | expected_games = build_game_structure(user_games, line_items)
25 | expect(body_json['games']).to contain_exactly *expected_games
26 | end
27 |
28 | it "does not return any non-user licenses" do
29 | get url, headers: auth_header(user)
30 | game = body_json['games'].select { |game| game['id'] == user_games.first.id }.first
31 | unexpected_licenses = non_user_line_items.map { |line_item| line_item.licenses.map(&:key) }.flatten
32 | expect(game['licenses']).to_not include *unexpected_licenses
33 | end
34 |
35 | it "returns success status" do
36 | get url, headers: auth_header(user)
37 | expect(response).to have_http_status(:ok)
38 | end
39 | end
40 |
41 | def build_game_structure(products, line_items)
42 | products.map do |product|
43 | json = product.as_json(only: %i[id name description])
44 | json['image_url'] = rails_blob_url(product.image)
45 | json.merge! product.productable.as_json(only: %i[mode developer release_date])
46 | json['system_requirement'] = product.productable.system_requirement.as_json
47 | game_licenses = line_items.select { |line_item| line_item.product_id == product.id }.map(&:licenses).flatten
48 | json.merge!({ 'licenses' => game_licenses.map(&:key) })
49 | json
50 | end
51 | end
52 | end
53 |
--------------------------------------------------------------------------------
/spec/requests/storefront/v1/games/unautheticated_requests_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe "Storefront V1 Games without authentication", type: :request do
4 |
5 | context "GET /games" do
6 | let(:url) { "/storefront/v1/games" }
7 | let!(:games) { create_list(:product, 5) }
8 |
9 | before(:each) { get url }
10 |
11 | include_examples "unauthenticated access"
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/spec/requests/storefront/v1/orders/authenticated_requests_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe "Storefront V1 Orders as authenticated user", type: :request do
4 | let(:user) { create(:user) }
5 |
6 | context "GET /orders" do
7 | let(:url) { "/storefront/v1/orders" }
8 | let!(:user_orders) { create_list(:order, 10, user: user) }
9 | let!(:non_user_orders) { create_list(:order, 10) }
10 |
11 | it "returns all user orders" do
12 | get url, headers: auth_header(user)
13 | expected_orders = user_orders.as_json(only: %i[id status total_amount payment_type])
14 | expect(body_json['orders']).to contain_exactly *expected_orders
15 | end
16 |
17 | it "does not return any non-user orders" do
18 | get url, headers: auth_header(user)
19 | unexpected_orders = non_user_orders.as_json(only: %i[id status total_amount payment_type])
20 | expect(body_json['orders']).to_not include *unexpected_orders
21 | end
22 |
23 | it "returns success status" do
24 | get url, headers: auth_header(user)
25 | expect(response).to have_http_status(:ok)
26 | end
27 | end
28 |
29 | context "GET /order/:id" do
30 | context "when user tries to access its own order" do
31 | let!(:coupon) { create(:coupon) }
32 | let!(:order) { create(:order, user: user, coupon: coupon) }
33 | let!(:line_items) { create_list(:line_item, 5, order: order) }
34 | let(:url) { "/storefront/v1/orders/#{order.id}" }
35 |
36 | it "returns requested Order" do
37 | get url, headers: auth_header(user)
38 | expected_line_items = line_items.map do |line_item|
39 | formatted = line_item.as_json(only: %i[quantity payed_price])
40 | formatted['product'] = line_item.product.name
41 | formatted
42 | end
43 | expected_order = order.as_json(only: %i[id status total_amount subtotal payment_type])
44 | .merge({ 'discount' => coupon.discount_value.to_f, 'line_items' => expected_line_items })
45 | expect(body_json['order']).to eq expected_order
46 | end
47 |
48 | it "returns success status" do
49 | get url, headers: auth_header(user)
50 | expect(response).to have_http_status(:ok)
51 | end
52 | end
53 |
54 | context "when user tries to access another user order" do
55 | let!(:another_user_order) { create(:order) }
56 | let(:url) { "/storefront/v1/orders/#{another_user_order.id}" }
57 |
58 | it "returns success status" do
59 | get url, headers: auth_header(user)
60 | expect(response).to have_http_status(:forbidden)
61 | end
62 | end
63 | end
64 | end
65 |
--------------------------------------------------------------------------------
/spec/requests/storefront/v1/orders/unautheticated_requests_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe "Storefront V1 Orders without authentication", type: :request do
4 |
5 | context "GET /orders" do
6 | let(:url) { "/storefront/v1/orders" }
7 | let!(:orders) { create_list(:order, 5) }
8 |
9 | before(:each) { get url }
10 |
11 | include_examples "unauthenticated access"
12 | end
13 |
14 | context "GET /orders/:id" do
15 | let(:order) { create(:order) }
16 | let(:url) { "/storefront/v1/orders/#{order.id}" }
17 |
18 | before(:each) { get url }
19 |
20 | include_examples "unauthenticated access"
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/spec/requests/storefront/v1/wish_items/unautheticated_requests_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe "Storefront V1 Wish Items without authentication", type: :request do
4 |
5 | context "GET /wish_items" do
6 | let(:url) { "/storefront/v1/wish_items" }
7 | let!(:wish_items) { create_list(:wish_item, 5) }
8 |
9 | before(:each) { get url }
10 |
11 | include_examples "unauthenticated access"
12 | end
13 |
14 | context "POST /wish_items" do
15 | let(:url) { "/storefront/v1/wish_items" }
16 |
17 | before(:each) { post url }
18 |
19 | include_examples "unauthenticated access"
20 | end
21 |
22 | context "DELETE /wish_items/:id" do
23 | let!(:wish_item) { create(:wish_item) }
24 | let(:url) { "/storefront/v1/wish_items/#{wish_item.id}" }
25 |
26 | before(:each) { delete url }
27 |
28 | include_examples "unauthenticated access"
29 | end
30 | end
31 |
--------------------------------------------------------------------------------
/spec/services/admin/alocate_licenses_service_spec.rb:
--------------------------------------------------------------------------------
1 | require "rails_helper"
2 |
3 | describe Admin::AlocateLicensesService do
4 | context "when #call" do
5 | let!(:order) { create(:order) }
6 | let!(:line_item) { create(:line_item, order: order) }
7 | let!(:licenses) { create_list(:license, line_item.quantity, game: line_item.product.productable) }
8 |
9 | it "allocates same number of licenses as line item quantity" do
10 | expect do
11 | described_class.new(line_item).call
12 | end.to change(line_item.licenses, :count).by(line_item.quantity)
13 | end
14 |
15 | it "licenses receives :in_use status" do
16 | described_class.new(line_item).call
17 | licenses_status = line_item.licenses.pluck(:status).uniq
18 | expect(licenses_status).to eq ['in_use']
19 | end
20 |
21 | it "line item receives :delivered status" do
22 | described_class.new(line_item).call
23 | line_item.reload
24 | expect(line_item.status).to eq 'delivered'
25 | end
26 |
27 | it "send an email for each allocated license" do
28 | described_class.new(line_item).call
29 | line_item.licenses.each do |license|
30 | expect(ActionMailer::MailDeliveryJob).to have_been_enqueued.with(
31 | 'LicenseMailer', 'send_license', 'deliver_now', { params: { license: license }, args: [] }
32 | )
33 | end
34 | end
35 | end
36 | end
--------------------------------------------------------------------------------
/spec/services/admin/dashboard/sales_range_service_spec.rb:
--------------------------------------------------------------------------------
1 | require "rails_helper"
2 |
3 | describe Admin::Dashboard::SalesRangeService do
4 | context "#call" do
5 | context "when range is less than 30 days" do
6 | let(:min_date) { 20.days.ago }
7 | let(:max_date) { Date.current }
8 |
9 | let(:product) { create(:product) }
10 |
11 | let!(:sales_line_items) do
12 | 20.downto(1).map do |num|
13 | order = create(:order, created_at: num.days.ago)
14 | order.update_column(:status, :finished)
15 | create(:line_item, order: order, product: product, payed_price: 200, quantity: num)
16 | end
17 | end
18 |
19 | it "returns data grouped by day" do
20 | expected_return = sales_line_items.map do |line_item|
21 | day = line_item.order.created_at.strftime("%Y-%m-%d")
22 | total_sold = line_item.payed_price * line_item.quantity
23 | { date: day, total_sold: total_sold.to_f }
24 | end
25 | service = described_class.new(min: min_date, max: max_date)
26 | service.call
27 | expect(service.records).to eq expected_return
28 | end
29 | end
30 |
31 | context "when range is greater than 30 days" do
32 | let(:min_date) { 5.months.ago }
33 | let(:max_date) { Date.current }
34 |
35 | let(:product) { create(:product) }
36 |
37 | let!(:sales_line_items) do
38 | 5.downto(1).map do |num|
39 | order = create(:order, created_at: num.months.ago)
40 | order.update_column(:status, :finished)
41 | create(:line_item, order: order, product: product, payed_price: 200, quantity: num)
42 | end
43 | end
44 |
45 | it "returns data grouped by month" do
46 | expected_return = sales_line_items.map do |line_item|
47 | month = line_item.order.created_at.strftime("%Y-%m")
48 | total_sold = line_item.payed_price * line_item.quantity
49 | { date: month, total_sold: total_sold.to_f }
50 | end
51 | service = described_class.new(min: min_date, max: max_date)
52 | service.call
53 | expect(service.records).to eq expected_return
54 | end
55 | end
56 | end
57 |
58 | def build_product(line_item)
59 | total_sold = line_item.quantity * line_item.payed_price
60 | product = line_item.product
61 | product_image = Rails.application.routes.url_helpers.rails_blob_path(product.image, only_path: false)
62 | { product: product.name, image: product_image, quantity: line_item.quantity, total_sold: total_sold }
63 | end
64 | end
--------------------------------------------------------------------------------
/spec/services/admin/dashboard/summary_service_spec.rb:
--------------------------------------------------------------------------------
1 | require "rails_helper"
2 |
3 | describe Admin::Dashboard::SummaryService do
4 | let(:min_date) { 7.days.ago }
5 | let(:max_date) { Date.current }
6 |
7 | context "#call" do
8 | it "returns users count follwing range date" do
9 | users_to_count = create_list(:user, 10, created_at: 2.days.ago)
10 | users_out_of_range = create_list(:user, 5, created_at: 8.days.ago)
11 | service = described_class.new(min: min_date, max: max_date)
12 | service.call
13 | expect(service.records[:users]).to eq users_to_count.size
14 | end
15 |
16 | it "returns products count following range date" do
17 | products_to_count = create_list(:product, 10, created_at: 2.days.ago)
18 | products_out_of_range = create_list(:product, 5, created_at: 8.days.ago)
19 | service = described_class.new(min: min_date, max: max_date)
20 | service.call
21 | expect(service.records[:products]).to eq products_to_count.size
22 | end
23 |
24 | it "returns orders count following range date and order :finished status" do
25 | orders_to_count = create_list(:order, 10, created_at: 2.days.ago)
26 | orders_to_count.each { |order| order.update_column(:status, :finished) }
27 | unfinished_orders = create_list(:order, 7, created_at: 2.days.ago)
28 | orders_out_of_range = create_list(:order, 5, created_at: 8.days.ago)
29 | service = described_class.new(min: min_date, max: max_date)
30 | service.call
31 | expect(service.records[:orders]).to eq orders_to_count.size
32 | end
33 |
34 | it "returns profit following range date and order :finished status" do
35 | orders_to_sum = create_list(:order, 10, created_at: 2.days.ago, total_amount: 65.43)
36 | orders_to_sum.each { |order| order.update_column(:status, :finished) }
37 | unfinished_orders = create_list(:order, 7, created_at: 2.days.ago, total_amount: 76.12)
38 | orders_out_of_range = create_list(:order, 5, created_at: 8.days.ago, total_amount: 43.12)
39 | service = described_class.new(min: min_date, max: max_date)
40 | service.call
41 | expected_amount = orders_to_sum.sum(&:total_amount)
42 | expect(service.records[:profit]).to eq expected_amount
43 | end
44 | end
45 | end
--------------------------------------------------------------------------------
/spec/services/admin/dashboard/top_five_products_service_spec.rb:
--------------------------------------------------------------------------------
1 | require "rails_helper"
2 |
3 | describe Admin::Dashboard::TopFiveProductsService do
4 | let(:min_date) { 7.days.ago }
5 | let(:max_date) { Date.current }
6 |
7 | context "#call" do
8 | let(:top_five_products) { create_list(:product, 5) }
9 | let(:less_sold_products) { create_list(:product, 5) }
10 | let(:order) do
11 | order = create(:order, created_at: 4.days.ago)
12 | order.update_column(:status, :finished)
13 | order
14 | end
15 | let!(:top_five_line_itens) do
16 | top_five_products.map.with_index do |product, index|
17 | create(:line_item, payed_price: 200, quantity: (index + 1), order: order, product: product)
18 | end
19 | end
20 | let(:out_of_date_order) do
21 | order = create(:order, created_at: 8.days.ago)
22 | order.update_column(:status, :finished)
23 | order
24 | end
25 | let!(:out_of_date_line_items) do
26 | less_sold_products.map.with_index do |product, index|
27 | create(:line_item, payed_price: 2000, quantity: (index + 1), order: out_of_date_order, product: product)
28 | end
29 | end
30 |
31 | it "returns right sold products follwing range date" do
32 | expected_return = top_five_line_itens.reverse.map do |line_item|
33 | build_product(line_item)
34 | end
35 | service = described_class.new(min: min_date, max: max_date)
36 | service.call
37 | expect(service.records).to eq expected_return
38 | end
39 |
40 | it "does not return any product out of range date" do
41 | unexpected_return = out_of_date_line_items.reverse.map do |line_item|
42 | build_product(line_item)
43 | end
44 | service = described_class.new(min: min_date, max: max_date)
45 | service.call
46 | expect(service.records).to_not include *unexpected_return
47 | end
48 | end
49 |
50 | def build_product(line_item)
51 | total_sold = line_item.quantity * line_item.payed_price
52 | product = line_item.product
53 | product_image = Rails.application.routes.url_helpers.rails_blob_url(product.image, host: "localhost", port: 3000)
54 | { product: product.name, image: product_image, quantity: line_item.quantity, total_sold: total_sold }
55 | end
56 | end
57 |
--------------------------------------------------------------------------------
/spec/services/admin/finish_delivered_orders_service_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe Admin::FinishDeliveredOrdersService do
4 | context "#call" do
5 | let!(:order) { create(:order) }
6 | let!(:delivered_line_items) { create_list(:line_item, 2, order: order) }
7 |
8 | before(:each) do
9 | order.update!(status: :payment_accepted)
10 | delivered_line_items.each { |line_item| line_item.update!(status: :delivered) }
11 | end
12 |
13 | it "set order as :finished when all line items are :delived" do
14 | described_class.call
15 | order.reload
16 | expect(order.status).to eq 'finished'
17 | end
18 |
19 | it "does not set order as :finished when at least one line item is not delived yet" do
20 | create(:line_item, order: order, status: :preparing)
21 | described_class.call
22 | order.reload
23 | expect(order.status).to_not eq 'finished'
24 | end
25 |
26 | it "does not set order as :finished until it is on :payment_accepted status" do
27 | order.update!(status: :processing_order)
28 | described_class.call
29 | order.reload
30 | expect(order.status).to eq 'processing_order'
31 | end
32 | end
33 | end
34 |
--------------------------------------------------------------------------------
/spec/shared_examples/forbidden_access_example.rb:
--------------------------------------------------------------------------------
1 | shared_examples "forbidden access" do
2 | it "returns error message" do
3 | expect(body_json['errors']['message']).to eq "Forbidden access"
4 | end
5 |
6 | it "returns forbidden status" do
7 | expect(response).to have_http_status(:forbidden)
8 | end
9 | end
--------------------------------------------------------------------------------
/spec/shared_examples/like_searchable_concern_example.rb:
--------------------------------------------------------------------------------
1 | shared_examples "like searchable concern" do |factory_name, field|
2 | let!(:search_param) { "Example" }
3 | let!(:records_to_find) do
4 | (0..3).to_a.map { |index| create(factory_name, field => "Example #{index}") }
5 | end
6 | let!(:records_to_ignore) { create_list(factory_name, 3) }
7 |
8 | it "found records with expression in :#{field}" do
9 | found_records = described_class.like(field, search_param)
10 | expect(found_records.to_a).to contain_exactly(*records_to_find)
11 | end
12 |
13 | it "ignores records without expression in :#{field}" do
14 | found_records = described_class.like(field, search_param)
15 | expect(found_records.to_a).to_not include(*records_to_ignore)
16 | end
17 | end
--------------------------------------------------------------------------------
/spec/shared_examples/pagination_meta_attributes_examples.rb:
--------------------------------------------------------------------------------
1 | shared_examples "pagination meta attributes" do |pagination_attr|
2 | it "returns :meta attribute with right pagination data" do
3 | pagination_attr.stringify_keys!
4 | expect(body_json['meta']).to include(pagination_attr)
5 | end
6 | end
--------------------------------------------------------------------------------
/spec/shared_examples/sign_in_examples.rb:
--------------------------------------------------------------------------------
1 | shared_examples "sign in" do |email, password|
2 | let(:url) { '/auth/v1/user/sign_in' }
3 |
4 | context "when :email and :password are right" do
5 | it "retuns user tokens on header" do
6 | post url, params: { email: email, password: password }
7 | sign_in_headers = %W(access-token token-type client expiry uid)
8 | expect(response.headers).to include(*sign_in_headers)
9 | end
10 |
11 | it "returns :ok status" do
12 | post url, params: { email: email, password: password }
13 | expect(response).to have_http_status(:ok)
14 | end
15 | end
16 |
17 | context "with invalid credentials" do
18 | it "does not return token on header" do
19 | post url, params: { email: "", password: password }
20 | sign_in_headers = %W(access-token token-type client expiry uid)
21 | expect(response.headers).to_not include(*sign_in_headers)
22 | end
23 |
24 | it "returns :unauthenticated status" do
25 | post url, params: { email: "", password: password }
26 | expect(response).to have_http_status(:unauthorized)
27 | end
28 | end
29 | end
--------------------------------------------------------------------------------
/spec/shared_examples/unauthenticated_access_example.rb:
--------------------------------------------------------------------------------
1 | shared_examples "unauthenticated access" do
2 | it "returns unauthorized status" do
3 | expect(response).to have_http_status(:unauthorized)
4 | end
5 | end
--------------------------------------------------------------------------------
/spec/support/factory_bot.rb:
--------------------------------------------------------------------------------
1 | RSpec.configure do |config|
2 | config.include FactoryBot::Syntax::Methods
3 | end
--------------------------------------------------------------------------------
/spec/support/images/product_image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OneBitCodeBlog/e-commerce-Api-Dev/cf15a94a7f2f7ac43089ab4cdb7e7176afbc8bee/spec/support/images/product_image.png
--------------------------------------------------------------------------------
/spec/support/request_api.rb:
--------------------------------------------------------------------------------
1 | module RequestAPI
2 | def body_json(symbolize_keys: false)
3 | json = JSON.parse(response.body)
4 | symbolize_keys ? json.deep_symbolize_keys : json
5 | rescue
6 | return {}
7 | end
8 |
9 | def auth_header(user = nil, merge_with: {})
10 | user ||= create(:user)
11 | auth = user.create_new_auth_token
12 | header = auth.merge({ 'Content-Type' => 'application/json', 'Accept' => 'application/json' })
13 | header.merge merge_with
14 | end
15 |
16 | def unauthenticated_header(merge_with: {})
17 | default_header = { 'Content-Type' => 'application/json', 'Accept' => 'application/json' }
18 | default_header.merge merge_with
19 | end
20 | end
21 |
22 | RSpec.configure do |config|
23 | config.include RequestAPI, type: :request
24 | end
--------------------------------------------------------------------------------
/spec/support/shoulda_matchers.rb:
--------------------------------------------------------------------------------
1 | Shoulda::Matchers.configure do |config|
2 | config.integrate do |with|
3 | with.test_framework :rspec
4 | with.library :rails
5 | end
6 | end
--------------------------------------------------------------------------------
/spec/support/time_helpers.rb:
--------------------------------------------------------------------------------
1 | RSpec.configure do |config|
2 | config.include ActiveSupport::Testing::TimeHelpers
3 | end
--------------------------------------------------------------------------------
/spec/validators/cpf_cnpj_validator_spec.rb:
--------------------------------------------------------------------------------
1 | require "rails_helper"
2 |
3 | class Validatable
4 | include ActiveModel::Validations
5 | attr_accessor :document
6 | validates :document, cpf_cnpj: true
7 | end
8 |
9 | describe CpfCnpjValidator do
10 | subject { Validatable.new }
11 |
12 | context "when it is an invalid CPF" do
13 | before { subject.document = "431.321.551-12" }
14 |
15 | it "should be invalid" do
16 | expect(subject.valid?).to be_falsey
17 | end
18 |
19 | it "adds an error on model" do
20 | subject.valid?
21 | expect(subject.errors.keys).to include(:document)
22 | end
23 | end
24 |
25 | context "when it is an invalid CNPJ" do
26 | before { subject.document = "27.021.724/0001-53" }
27 |
28 | it "should be invalid" do
29 | expect(subject.valid?).to be_falsey
30 | end
31 |
32 | it "adds an error on model" do
33 | subject.valid?
34 | expect(subject.errors.keys).to include(:document)
35 | end
36 | end
37 |
38 | context "when it's does not have CPF or CNPJ format" do
39 | before { subject.document = "431.321" }
40 |
41 | it "should be invalid" do
42 | expect(subject.valid?).to be_falsey
43 | end
44 |
45 | it "adds an error on model" do
46 | subject.valid?
47 | expect(subject.errors.keys).to include(:document)
48 | end
49 | end
50 |
51 | it "is valid when it is a CPF" do
52 | subject.document = "865.922.358-61"
53 | expect(subject.valid?).to be_truthy
54 | end
55 |
56 | it "is valid when it is a CNPJ" do
57 | subject.document = "27.021.724/0001-78"
58 | expect(subject.valid?).to be_truthy
59 | end
60 | end
--------------------------------------------------------------------------------
/spec/validators/future_date_validator_spec.rb:
--------------------------------------------------------------------------------
1 | require "rails_helper"
2 |
3 | class Validatable
4 | include ActiveModel::Validations
5 | attr_accessor :date
6 | validates :date, future_date: true
7 | end
8 |
9 | describe FutureDateValidator do
10 | subject { Validatable.new }
11 |
12 | context "when date is before current date" do
13 | before { subject.date = 1.day.ago }
14 |
15 | it "should be invalid" do
16 | expect(subject.valid?).to be_falsey
17 | end
18 |
19 | it "adds an error on model" do
20 | subject.valid?
21 | expect(subject.errors.keys).to include(:date)
22 | end
23 | end
24 |
25 | context "when date is equal current date" do
26 | before { subject.date = Time.zone.now }
27 |
28 | it "should be invalid" do
29 | expect(subject.valid?).to be_falsey
30 | end
31 |
32 | it "adds an error on model" do
33 | subject.valid?
34 | expect(subject.errors.keys).to include(:date)
35 | end
36 | end
37 |
38 | context "when date is greater than current date" do
39 | before { subject.date = Time.zone.now + 1.day }
40 |
41 | it "should be valid" do
42 | expect(subject.valid?).to be_truthy
43 | end
44 | end
45 | end
--------------------------------------------------------------------------------
/storage/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OneBitCodeBlog/e-commerce-Api-Dev/cf15a94a7f2f7ac43089ab4cdb7e7176afbc8bee/storage/.keep
--------------------------------------------------------------------------------
/tmp/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OneBitCodeBlog/e-commerce-Api-Dev/cf15a94a7f2f7ac43089ab4cdb7e7176afbc8bee/tmp/.keep
--------------------------------------------------------------------------------
/tmp/pids/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OneBitCodeBlog/e-commerce-Api-Dev/cf15a94a7f2f7ac43089ab4cdb7e7176afbc8bee/tmp/pids/.keep
--------------------------------------------------------------------------------
/vendor/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OneBitCodeBlog/e-commerce-Api-Dev/cf15a94a7f2f7ac43089ab4cdb7e7176afbc8bee/vendor/.keep
--------------------------------------------------------------------------------