Skip to content

Commit

Permalink
feat: add ranking new features
Browse files Browse the repository at this point in the history
  • Loading branch information
mewthu2 committed Apr 29, 2024
1 parent b6e331b commit cb94486
Show file tree
Hide file tree
Showing 8 changed files with 369 additions and 107 deletions.
5 changes: 3 additions & 2 deletions app/controllers/dashboard_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,15 @@ def update_order_markups
def product_ranking; end

def product_ranking_spreadsheet
send_data(ProductRankingSpreadsheetJob.perform_now(params[:year]),
send_data(ProductRankingSpreadsheetJob.perform_now(params[:year], params[:kind]),
disposition: %(attachment; filename=products_ranking_#{DateTime.now}.xlsx))
end

private

def product_ranking_references
@product_sales = ProductSale.where(kind: params[:interval] == 'all' ? ['seven_days', 'thirty_days'] : params[:interval],
@product_sales = ProductSale.where(kind: params[:interval],
week_refference: params[:week_refference].present? ? params[:week_refference] : nil,
month_refference: params[:month_refference].present? ? params[:month_refference] : Date.today.strftime('%B'),
year_refference: params[:year_refference].present? ? params[:year_refference] : Date.today.year)
.joins(:product)
Expand Down
55 changes: 54 additions & 1 deletion app/jobs/product_ranking_spreadsheet_job.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
class ProductRankingSpreadsheetJob < ApplicationJob
queue_as :default

def perform(year)
def perform(year, kind)
if kind == 'thirty_days'
generate_thirty_days_data(year)
elsif kind == 'seven_days'
generate_seven_days_data(year)
else
raise ArgumentError, "Invalid 'kind' parameter. Please specify either 'thirty_days' or 'seven_days'."
end
end

private

def generate_thirty_days_data(year)
product_sales = ProductSale.includes(:product)
.where(year_refference: year)
.group_by { |sale| sale&.product_id }
Expand Down Expand Up @@ -50,4 +62,45 @@ def perform(year)

workbook.stream.read
end

def generate_seven_days_data(year)
product_sales = ProductSale.includes(:product)
.where(year_refference: year, kind: 'seven_days')
.group_by { |sale| [sale.product_id, sale.week_refference] }

workbook = RubyXL::Workbook.new
tab = workbook.worksheets[0]
tab.sheet_name = 'Product Sales Spreadsheet'

header = ['Product Name',
'SKU',
'Fulfillment Channel',
'ASIN1',
'Month',
'Week',
'Units Sold']

header.each_with_index { |data, col| tab.add_cell(0, col, data) }

row_index = 1

product_sales.each_value do |sales|
product = sales.first.product

sales.each do |sale|
tab.add_cell(row_index, 0, product.item_name)
tab.add_cell(row_index, 1, product.seller_sku)
tab.add_cell(row_index, 2, product.fulfillment_channel)
tab.add_cell(row_index, 3, product.asin1)

tab.add_cell(row_index, 4, sale.month_refference)
tab.add_cell(row_index, 5, sale.week_refference)
tab.add_cell(row_index, 6, sale.unit_count)

row_index += 1
end
end

workbook.stream.read
end
end
105 changes: 95 additions & 10 deletions app/jobs/update_product_sales_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,25 @@ def perform(kind, month)
def update_product_sales_info(kind, month)
case kind
when 'thirty_days'
update_thirty_days_sales(kind, month)
update_thirty_days_sales(month)
when 'seven_days'
update_seven_days_sales(month)
end
end

def update_thirty_days_sales(kind, month)
def update_thirty_days_sales(month)
products = Product.where(status: 'Active')

data_refference = month.present? ? Date.new(Date.today.year, month, 1) : Date.today.prev_month
data_reference = month.present? ? Date.new(Date.today.year, month, 1) : Date.today.prev_month

start_date = data_refference.beginning_of_month.strftime('%Y-%m-%dT00:00:00Z')
end_date = data_refference.end_of_month.strftime('%Y-%m-%dT%H:%M:%SZ')
start_date = data_reference.beginning_of_month.strftime('%Y-%m-%dT00:00:00Z')
end_date = data_reference.end_of_month.strftime('%Y-%m-%dT%H:%M:%SZ')
date_range = "#{start_date}--#{end_date}"

products.each do |prd|
next if ProductSale.where(product_id: prd.id, month_refference: data_refference.strftime('%B'), year_refference: Date.today.year, kind:).present?
next if ProductSale.where(product_id: prd.id, month_refference: data_reference.strftime('%B'), year_refference: Date.today.year, kind: 'thirty_days').present?

p('sleeping for 1 seconds...')
p('Sleeping for 1 second...')
sleep(1.seconds)

request_params = {
Expand All @@ -42,16 +44,99 @@ def update_thirty_days_sales(kind, month)

next unless response['payload'].present?

update_or_create_product_sale(prd, nil, date_range, data, kind, data_refference)
update_or_create_product_sale(prd, nil, date_range, data, 'thirty_days', data_reference)
end
end

def update_seven_days_sales(month = nil)
products = Product.where(status: 'Active')

if month.nil?
# Calcula a data de início e fim da semana passada
last_week_start = (Date.today - 1.week).beginning_of_week
last_week_end = (Date.today - 1.week).end_of_week

week_number = 1

date_range = "#{last_week_start.strftime('%Y-%m-%dT00:00:00Z')}--#{last_week_end.strftime('%Y-%m-%dT%H:%M:%SZ')}"

products.each do |prd|
next if ProductSale.where(product_id: prd.id,
week_refference: week_number,
kind: 'seven_days',
month_refference: month_start.strftime('%B'),
year_refference: Date.today.year).present?

p('Sleeping for 1 second...')
sleep(1.seconds)

request_params = {
granularity: 'total',
interval: date_range,
marketplaceIds: ENV['MARKETPLACE_ID'],
sku: prd.seller_sku
}

endpoint = 'https://sellingpartnerapi-na.amazon.com/sales/v1/orderMetrics'

response = HTTParty.get(endpoint, query: request_params,
headers: { 'x-amz-access-token' => @access_token })
data = response['payload']&.first

next unless response['payload'].present?

update_or_create_product_sale(prd, week_number, date_range, data, 'seven_days', last_week_start)
end
else
month_start = Date.new(Date.today.year, month, 1)
weeks_in_month = (month_start..month_start.end_of_month).each_slice(7)

week_number = 1

weeks_in_month.each do |week|
start_date = week.first.strftime('%Y-%m-%dT00:00:00Z')
end_date = week.last.strftime('%Y-%m-%dT%H:%M:%SZ')
date_range = "#{start_date}--#{end_date}"

products.each do |prd|
product_sale = ProductSale.where(product_id: prd.id,
week_refference: week_number,
kind: 'seven_days',
interval: date_range,
month_refference: month_start.strftime('%B'),
year_refference: Date.today.year)
next if product_sale.present?

p('Sleeping for 1 second...')
sleep(1.seconds)

request_params = {
granularity: 'total',
interval: date_range,
marketplaceIds: ENV['MARKETPLACE_ID'],
sku: prd.seller_sku
}

endpoint = 'https://sellingpartnerapi-na.amazon.com/sales/v1/orderMetrics'

response = HTTParty.get(endpoint, query: request_params,
headers: { 'x-amz-access-token' => @access_token })
data = response['payload']&.first

next unless response['payload'].present?
update_or_create_product_sale(prd, week_number, date_range, data, 'seven_days', month_start)
end
week_number += 1
end
end
end

private

def update_or_create_product_sale(prd, week_of_month, date_range, data, kind, data_refference)
def update_or_create_product_sale(prd, week_of_month, date_range, data, kind, data_reference)
ProductSale.find_or_create_by(product_id: prd.id,
kind:,
month_refference: data_refference.strftime('%B'),
month_refference: data_reference.strftime('%B'),
week_refference: week_of_month,
year_refference: Date.today.year,
interval: date_range,
Expand Down
2 changes: 1 addition & 1 deletion app/models/product_sale.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ class ProductSale < ApplicationRecord
# Associacoes
belongs_to :product
# Validacoes
validates :product_id, uniqueness: { scope: [:kind, :month_refference, :year_refference], message: 'Já existe um dado de venda deste tipo para este produto neste período.' }
validates :product_id, uniqueness: { scope: [:kind, :month_refference, :year_refference, :week_refference], message: 'Já existe um dado de venda deste tipo para este produto neste período.' }
# Escopos

# Metodos estaticos
Expand Down
95 changes: 95 additions & 0 deletions app/views/dashboard/partials/_seven_days.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<div class="container">
<%= form_tag(product_ranking_dashboard_index_path, method: 'get', id: 'search-form' ) do %>
<div class="card mb-lg advanced-search-form bg-dark text-light" id="filters">
<div class="card-header text-info d-flex justify-content-center">
Pesquisa avançada
</div>
<div class="card-body">
<div class="row">
<div class="col-6 col-md-2">
<%= label_tag :interval, 'Intervalo' %>
<%= select_tag :interval, options_for_select(
[['7 dias', 'seven_days']],
params[:interval]
), include_blank: false, class: 'form-control chosen-select'
%>
</div>
<div class="col-6 col-md-2">
<%= label_tag :month_refference, 'Mês de referência' %>
<%= select_tag :month_refference, options_for_select(Date::MONTHNAMES.compact.map(&:titleize), (params[:month_refference].presence || 1.month.ago.strftime('%B'))), include_blank: false, class: 'form-control chosen-select' %>
</div>
<div class="col-3 col-md-2">
<%= label_tag :week_refference, 'Semana' %>
<%= select_tag :week_refference, options_for_select(
[['Semana 1', '1'], ['Semana 2', '2'], ['Semana 3', '3'], ['Semana 4', '4'], ['Semana 5', '5']],
params[:interval]
), include_blank: false, class: 'form-control chosen-select'
%>
</div>
<div class="col-3 col-md-2">
<%= label_tag :year_refference, 'Ano de referência?' %>
<%= select_tag :year_refference, options_for_select(['Todos',
Date.today.year.to_s, (Date.today.year + 1).to_s,
(Date.today.year + 2).to_s, (Date.today.year + 3).to_s],
(params[:year_refference].presence || Date.today.year.to_s)),
include_blank: false, class: 'form-control chosen-select'
%>
</div>
<div class="col-12 col-md-4">
<%= label_tag :search, 'Procurar' %>
<%= text_field_tag :search, params[:search], class: 'form-control', placeholder: 'Pesquisar', autofocus: true %>
</div>
</div>
</div>
</div>
<div class="card-footer">
<%= button_tag class: 'btn btn-secondary text-info', name: '' do %><i class="fa fa-search text-info"></i> Pesquisar<% end %>
<%= button_tag formaction: product_ranking_spreadsheet_dashboard_index_path(year: '2024', kind: 'seven_days'), formmethod: :post, class: 'btn btn-success' do %><i class="fa fa-file-excel "></i> <b>Semanal</b> - Gerar Planilha 2024<% end %>
</div>
<% end %>
<div class="row">
<div class="col-12">
<table class="table table-dark table-hover table-responsive table-striped" style="overflow-x: scroll;" id="products-table">
<thead>
<tr>
<th class="text-center"><i class="fa fa-ellipsis-v"></i></th>
<th class="text-center"><%= 'Semana' %></th>
<th class="text-center"><%= 'Unidades vendidas' %></th>
<th class="text-center"><%= 'Produto' %></th>
<th class="text-center"><%= 'ASIN' %></th>
<th class="text-center"><%= 'Armazém' %></th>
<th class="text-center"><%= 'Mês/Ano de refernência' %></th>
</tr>
</thead>
<tbody>
<% product_sales.each do |product_sale| %>
<tr>
<td class="text-center">
<div class="btn-group" role="group" aria-label="Basic example">
<%= link_to edit_product_path(product_sale.product), class: 'btn btn-light btn-sm text-dark' do %> <i class="fas fa-edit"></i><% end %>
<% if product_sale.product.supplier_url.present? %>
<%= link_to product_sale.product.supplier_url, class: 'btn btn-light btn-sm text-dark', target:'_blank' do %> <i class="fa-brands fa-internet-explorer"></i><% end %>
<% end %>
</div>
</td>
<td class="text-center"><%= product_sale.week_refference %></td>
<td class="text-center"><span class="badge bg-dark text-warning" style="font-size: 20px !important;"><%= product_sale.unit_count %></span></td>
<td class="text-center" width="400"><%= ActionController::Base.helpers.truncate(product_sale.product.item_name, length: 120, omission: '...') %></td>
<td class="text-center"><%= product_sale.product.asin1 %></td>
<td class="text-center"><%= product_sale.product.fulfillment_channel == 'FBA' ? %(<span class="badge bg-primary"><i class="fa-brands fa-amazon"></i> FBA</span>).html_safe : %(<span class="badge bg-secondary"><i class="fas fa-globe-americas"></i> FBM</span>).html_safe %></td>
<td class="text-center"><%= product_sale.month_refference %> / <%= product_sale.year_refference %></td>
</tr>
<% end %>
</tbody>
<tfoot>
<tr>
<th colspan="14">

</th>
</tr>
</tfoot>
</table>
</div>
</div>
</div>

Loading

0 comments on commit cb94486

Please sign in to comment.