Filter sales data by dates

This commit is contained in:
Maikel Linke
2024-08-30 14:30:18 +10:00
parent 1016656781
commit d52134dad8
6 changed files with 187 additions and 18 deletions

View File

@@ -3,10 +3,27 @@
module DfcProvider
# Aggregates anonymised sales data for a research project.
class AffiliateSalesDataController < DfcProvider::ApplicationController
rescue_from Date::Error, with: -> { head :bad_request }
def show
person = AffiliateSalesDataBuilder.person(current_user)
person = AffiliateSalesDataBuilder.person(current_user, filter_params)
render json: DfcIo.export(person)
end
private
def filter_params
{
start_date: parse_date(params[:startDate]),
end_date: parse_date(params[:endDate]),
}
end
def parse_date(string)
return if string.blank?
Date.parse(string)
end
end
end

View File

@@ -2,17 +2,16 @@
class AffiliateSalesDataBuilder < DfcBuilder
class << self
def person(user)
DataFoodConsortium::Connector::Person.new(
urls.affiliate_sales_data_url,
affiliatedOrganizations: enterprises(user.affiliate_enterprises)
)
end
def enterprises(enterprises)
AffiliateSalesQuery.data(enterprises).map do |row|
def person(user, filters = {})
data = AffiliateSalesQuery.data(user.affiliate_enterprises, **filters)
suppliers = data.map do |row|
AffiliateSalesDataRowBuilder.new(row).build_supplier
end
DataFoodConsortium::Connector::Person.new(
urls.affiliate_sales_data_url,
affiliatedOrganizations: suppliers,
)
end
end
end

View File

@@ -2,11 +2,16 @@
class AffiliateSalesQuery
class << self
def data(enterprises)
def data(enterprises, start_date: nil, end_date: nil)
end_date = end_date&.end_of_day # Include the whole end date.
Spree::LineItem
.joins(tables)
.where(
spree_orders: { state: "complete", distributor_id: enterprises },
spree_orders: {
state: "complete", distributor_id: enterprises,
completed_at: [start_date..end_date],
},
)
.group(key_fields)
.pluck(fields)

View File

@@ -8,16 +8,53 @@ RSpec.describe "AffiliateSalesData", swagger_doc: "dfc.yaml", rswag_autodoc: tru
before { login_as user }
path "/api/dfc/affiliate_sales_data" do
parameter name: :startDate, in: :query, type: :string
parameter name: :endDate, in: :query, type: :string
get "Show sales data of person's affiliate enterprises" do
produces "application/json"
response "200", "successful" do
run_test! do
expect(json_response).to include(
"@id" => "http://test.host/api/dfc/affiliate_sales_data",
"@type" => "dfc-b:Person",
)
response "200", "successful", feature: :affiliate_sales_data do
let(:startDate) { Date.yesterday }
let(:endDate) { Time.zone.today }
before do
order = create(:order_with_totals_and_distribution, :completed)
ConnectedApps::AffiliateSalesData.new(
enterprise: order.distributor
).connect({})
end
context "with date filters" do
let(:startDate) { Date.tomorrow }
let(:endDate) { Date.tomorrow }
run_test! do
expect(json_response).to include(
"@id" => "http://test.host/api/dfc/affiliate_sales_data",
"@type" => "dfc-b:Person",
)
expect(json_response["dfc-b:affiliates"]).to eq nil
end
end
context "not filtered" do
run_test! do
expect(json_response).to include(
"@id" => "http://test.host/api/dfc/affiliate_sales_data",
"@type" => "dfc-b:Person",
)
expect(json_response["dfc-b:affiliates"]).to be_present
end
end
end
response "400", "bad request" do
let(:startDate) { "yesterday" }
let(:endDate) { "tomorrow" }
run_test!
end
end
end

View File

@@ -5,6 +5,43 @@ require_relative "../spec_helper"
RSpec.describe AffiliateSalesQuery do
subject(:query) { described_class }
describe ".data" do
let(:order) { create(:order_with_totals_and_distribution, :completed) }
let(:today) { Time.zone.today }
let(:yesterday) { Time.zone.yesterday }
let(:tomorrow) { Time.zone.tomorrow }
it "returns data" do
# Test data creation takes time.
# So I'm executing more tests in one `it` block here.
# And make it simpler to call the subject many times:
count_rows = lambda do |**args|
query.data(order.distributor, **args).count
end
# Without any filters:
expect(count_rows.call).to eq 1
# From today:
expect(count_rows.call(start_date: today)).to eq 1
# Until today:
expect(count_rows.call(end_date: today)).to eq 1
# Just today:
expect(count_rows.call(start_date: today, end_date: today)).to eq 1
# Yesterday:
expect(count_rows.call(start_date: yesterday, end_date: yesterday)).to eq 0
# Until yesterday:
expect(count_rows.call(end_date: yesterday)).to eq 0
# From tomorrow:
expect(count_rows.call(start_date: tomorrow)).to eq 0
end
end
describe ".label_row" do
it "converts an array to a hash" do
row = [

View File

@@ -70,6 +70,15 @@ paths:
'404':
description: not found
"/api/dfc/affiliate_sales_data":
parameters:
- name: startDate
in: query
schema:
type: string
- name: endDate
in: query
schema:
type: string
get:
summary: Show sales data of person's affiliate enterprises
tags:
@@ -88,6 +97,71 @@ paths:
dfc-b:logo: ''
dfc-b:firstName: ''
dfc-b:familyName: ''
dfc-b:affiliates:
"@type": dfc-b:Enterprise
dfc-b:hasAddress:
"@type": dfc-b:Address
dfc-b:hasStreet: ''
dfc-b:hasPostalCode: '20170'
dfc-b:hasCity: ''
dfc-b:hasCountry: ''
dfc-b:latitude: 0.0
dfc-b:longitude: 0.0
dfc-b:region: ''
dfc-b:logo: ''
dfc-b:name: ''
dfc-b:hasDescription: ''
dfc-b:VATnumber: ''
dfc-b:supplies:
"@type": dfc-b:SuppliedProduct
dfc-b:name: 'Product #3 - 7198'
dfc-b:description: ''
dfc-b:hasQuantity:
"@type": dfc-b:QuantitativeValue
dfc-b:hasUnit: dfc-m:Gram
dfc-b:value: 1.0
dfc-b:alcoholPercentage: 0.0
dfc-b:lifetime: ''
dfc-b:usageOrStorageCondition: ''
dfc-b:totalTheoreticalStock: 0.0
dfc-b:concernedBy:
"@type": dfc-b:OrderLine
dfc-b:description: ''
dfc-b:quantity:
"@type": dfc-b:QuantitativeValue
dfc-b:hasUnit: dfc-m:Piece
dfc-b:value: 1.0
dfc-b:hasPrice:
"@type": dfc-b:QuantitativeValue
dfc-b:value: 10.0
dfc-b:partOf:
"@type": dfc-b:Order
dfc-b:orderNumber: ''
dfc-b:date: ''
dfc-b:belongsTo:
"@type": dfc-b:SaleSession
dfc-b:beginDate: ''
dfc-b:endDate: ''
dfc-b:quantity: 0.0
dfc-b:objectOf:
"@type": dfc-b:Coordination
dfc-b:coordinatedBy:
"@type": dfc-b:Enterprise
dfc-b:hasAddress:
"@type": dfc-b:Address
dfc-b:hasStreet: ''
dfc-b:hasPostalCode: '20170'
dfc-b:hasCity: ''
dfc-b:hasCountry: ''
dfc-b:latitude: 0.0
dfc-b:longitude: 0.0
dfc-b:region: ''
dfc-b:logo: ''
dfc-b:name: ''
dfc-b:hasDescription: ''
dfc-b:VATnumber: ''
'400':
description: bad request
"/api/dfc/enterprises/{enterprise_id}/catalog_items":
parameters:
- name: enterprise_id