Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
stAndrei committed Jan 21, 2015
1 parent 9c774ee commit e75b371
Show file tree
Hide file tree
Showing 16 changed files with 265 additions and 0 deletions.
4 changes: 4 additions & 0 deletions Gemfile
@@ -0,0 +1,4 @@
source 'https://rubygems.org'

gem 'framework', '0.0.7'
gem 'sqlite3'
61 changes: 61 additions & 0 deletions Gemfile.lock
@@ -0,0 +1,61 @@
GEM
remote: https://rubygems.org/
specs:
actionpack (3.2.21)
activemodel (= 3.2.21)
activesupport (= 3.2.21)
builder (~> 3.0.0)
erubis (~> 2.7.0)
journey (~> 1.0.4)
rack (~> 1.4.5)
rack-cache (~> 1.2)
rack-test (~> 0.6.1)
sprockets (~> 2.2.1)
activemodel (3.2.21)
activesupport (= 3.2.21)
builder (~> 3.0.0)
activerecord (3.2.21)
activemodel (= 3.2.21)
activesupport (= 3.2.21)
arel (~> 3.0.2)
tzinfo (~> 0.3.29)
activesupport (3.2.21)
i18n (~> 0.6, >= 0.6.4)
multi_json (~> 1.0)
arel (3.0.3)
awesome_print (1.2.0)
builder (3.0.4)
erubis (2.7.0)
framework (0.0.7)
actionpack (~> 3.2, >= 3.2.16)
activerecord (~> 3.2, >= 3.2.16)
activesupport (~> 3.2, >= 3.2.16)
awesome_print (~> 1.2, >= 1.2.0)
rake (~> 10.3, >= 10.3.2)
thor (~> 0.19, >= 0.19.1)
hike (1.2.3)
i18n (0.6.11)
journey (1.0.4)
multi_json (1.10.1)
rack (1.4.5)
rack-cache (1.2)
rack (>= 0.4)
rack-test (0.6.2)
rack (>= 1.0)
rake (10.4.2)
sprockets (2.2.3)
hike (~> 1.2)
multi_json (~> 1.0)
rack (~> 1.0)
tilt (~> 1.1, != 1.3.0)
sqlite3 (1.3.10)
thor (0.19.1)
tilt (1.4.1)
tzinfo (0.3.42)

PLATFORMS
ruby

DEPENDENCIES
framework (= 0.0.7)
sqlite3
99 changes: 99 additions & 0 deletions README.md
@@ -0,0 +1,99 @@
# The Task

This task is to build the fake business model and predict revenue. Find detailed task description at the bottom of this document.
If something is unclear or incorrect in the description below - change it the way you think it should be.
If something is taking too much time for you - drop, don't waste your time, work on other tasks.

------------------------------------------------------------------

# Business model description


### Basic terms

- Company - we are the company
- Client (meaning a set of clients) - the one who pay us money
- Job - Company does some job for a Client using __one__ subcontractor
- Subcontractor (set of subscontractors) - Guys who actually do all the job behind the scenes. Client does not know anything about contractor. Only Company deals with Subcontractor (always 1 Subcontractor for every single Job)

### Basic flow

- One of our clients requests a job
- Job can be accepted or rejected by our Company

### Job accepted scenario:

- Company accepted `start_date` of this job set by Client
- Company starts working on this job starting from requested `start_date`
- Company estimates and sets `end_date` to this Job
- Company sends invoice to the Client
- Invoice `due_amount` is equal to `rate_set_for_the_client$ * (end_date - start_date).days`
- Invoice gets `pending` status
- Client has to pay for this invoice on any date __before__ `end_date`
- Invoice hasn't been paid in time scenario:
- Invoice gets status `overdue`
- On each day after `end_date` we add `rate_set_for_the_client$` amount to the invoice
- The Client can't request any new job
- Invoice has been paid in time scenario:
- Invoice gets status `paid`
- Client has an ability to add a new job
- Company finds Subcontractor who is not too busy with other jobs: should have less than 3 jobs assigned
- The Subcontractor gets paid once the job assigned to him is done
- The Subcontractor is paid only for number of days he actually worked:
- Amount paid to subcontractor: `subcontractor.rate * (end_date - start_date).days`
- Company can change Job's `end_date`:
- Invoice `due_amount` should be recalculated accordingly
- If Client already paid for the Invoice:
- If `paid_amount > due_amount` then send money to virtual Client's "local" account (stored in our db)
- If `paid_amount < due_amount` change `invoice_status` back to `pending`
- Client gets discount once they paid for 3 jobs (as regular customer)
- Discount percentage is set in application config `config/application.yml`
- Client may loose discount if one of their invoices is marked as `overdue`

### Job rejected scenario:

- Company rejected Client's request
- Client has to create new job, the one which is rejected is no longer in use

## Finally your task:

Calculate the following values:

### Revenue

Revenue is calculated as `SUM(invoices.paid_amount) - SUM(subcontractor_payouts.amount)`.

### Gross sales

Gross sales is equal to `SUM(invoices.paid_amount)`

### Rejection rate

Percentage of jobs rejected by the Company

### Predicted revenue

Predict revenue for: next month, next year. Take any valid acceptable algorythm.

Also include in report:

- Standard deviation (if possible)
- Worst case / best case revenue

### Per user stats

Calculate for any given period (set by user):

- Top 5 best clients (based on total __revenue__ impact)
- Top 5 worst clients
- Best subcontractor (based on total __revenue__ impact). Think more about this one.
- Worst Client by number of overdue days at the current moment

## Required performance

Take 100000 Clients and 50000 working Subcontractors. Performance is acceptable if you feel comfortable with it :)

------------------------------------------------------------------

This app utilizes Framework v0.0.7 and rocks MIT license.

7 changes: 7 additions & 0 deletions Rakefile
@@ -0,0 +1,7 @@
# Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.

require 'framework'
require 'framework/rake'

Dir["#{Dir.pwd}/app/tasks/**/*.rake"].each(&method(:load))
3 changes: 3 additions & 0 deletions app/models/client.rb
@@ -0,0 +1,3 @@
class Client < ActiveRecord::Base
has_many :invoices
end
Empty file added app/models/concerns/.keep
Empty file.
4 changes: 4 additions & 0 deletions app/models/invoice.rb
@@ -0,0 +1,4 @@
class Invoice < ActiveRecord::Base
belongs_to :client
end

3 changes: 3 additions & 0 deletions app/tasks/hello.rake
@@ -0,0 +1,3 @@
task hello: :environment do
Framework::Logger.disappointment("Hello from: Framework v0.0.7")
end
16 changes: 16 additions & 0 deletions config/application.yml
@@ -0,0 +1,16 @@
development: &common
enable_logging: yes
autoload_paths:
- app/models
default_timezone: 'Pacific Time (US & Canada)'

test:
<<: *common
enable_logging: no

staging:
<<: *common

production:
<<: *common
enable_logging: no
25 changes: 25 additions & 0 deletions config/databases.yml
@@ -0,0 +1,25 @@
# Defult database is used by default.
# Any models locating at app/models root directory will point to this database by default.
default:
development: &common
adapter: sqlite3
database: the_task_development
min_messages: WARNING
pool: 5
encoding: unicode

test:
<<: *common
database: the_task_test

statistics:
development: &common
adapter: sqlite3
database: statistics_development
min_messages: WARNING
pool: 5
encoding: unicode

test:
<<: *common
database: statistics
11 changes: 11 additions & 0 deletions config/environment.rb
@@ -0,0 +1,11 @@
# Set up gems listed in the Gemfile.
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])

require 'framework'

Bundler.require(:default, Framework.env)

Framework::Application.new do |app|
app.init!
end
2 changes: 2 additions & 0 deletions config/initializers/time_zone.rb
@@ -0,0 +1,2 @@
# Sample usage of application config
Time.zone = Framework.app.config['default_timezone']
Empty file added db/migrate/.keep
Empty file.
15 changes: 15 additions & 0 deletions db/migrate/20141214070910_create_clients.rb
@@ -0,0 +1,15 @@
class CreateClients < Framework::Migration
use_database :default

def up
create_table :clients do |t|
t.string :name
t.integer :local_account_amount
t.timestamps
end
end

def down
drop_table :clients
end
end
15 changes: 15 additions & 0 deletions db/migrate/20141214071354_create_invoices.rb
@@ -0,0 +1,15 @@
class CreateInvoices < Framework::Migration
use_database :default

def up
create_table :invoices do |t|
t.integer :amount
t.references :client
t.timestamps
end
end

def down
drop_table :invoices
end
end
Empty file added lib/.keep
Empty file.

0 comments on commit e75b371

Please sign in to comment.