From adb856d784192d9b53179a7bfe759f1cee8a06cd Mon Sep 17 00:00:00 2001 From: Sergei Zinin Date: Sun, 14 Dec 2014 12:52:57 +0700 Subject: [PATCH 1/4] Initial commit --- Gemfile | 4 +++ Gemfile.lock | 61 ++++++++++++++++++++++++++++++++ README.md | 1 + Rakefile | 7 ++++ app/models/concerns/.keep | 0 app/tasks/hello.rake | 3 ++ config/application.yml | 16 +++++++++ config/databases.yml | 25 +++++++++++++ config/environment.rb | 11 ++++++ config/initializers/time_zone.rb | 2 ++ db/migrate/.keep | 0 lib/.keep | 0 12 files changed, 130 insertions(+) create mode 100644 Gemfile create mode 100644 Gemfile.lock create mode 100644 README.md create mode 100644 Rakefile create mode 100644 app/models/concerns/.keep create mode 100644 app/tasks/hello.rake create mode 100644 config/application.yml create mode 100644 config/databases.yml create mode 100644 config/environment.rb create mode 100644 config/initializers/time_zone.rb create mode 100644 db/migrate/.keep create mode 100644 lib/.keep diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ef83285 --- /dev/null +++ b/Gemfile @@ -0,0 +1,4 @@ +source 'https://rubygems.org' + +gem 'framework', '0.0.7' +gem 'sqlite3' diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..93c4891 --- /dev/null +++ b/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 diff --git a/README.md b/README.md new file mode 100644 index 0000000..6141e20 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +This app utilizes Framework v0.0.7 and rocks MIT license. \ No newline at end of file diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..f9b32dc --- /dev/null +++ b/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)) diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 diff --git a/app/tasks/hello.rake b/app/tasks/hello.rake new file mode 100644 index 0000000..9b4751b --- /dev/null +++ b/app/tasks/hello.rake @@ -0,0 +1,3 @@ +task hello: :environment do + Framework::Logger.disappointment("Hello from: Framework v0.0.7") +end diff --git a/config/application.yml b/config/application.yml new file mode 100644 index 0000000..0ed5341 --- /dev/null +++ b/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 diff --git a/config/databases.yml b/config/databases.yml new file mode 100644 index 0000000..68df898 --- /dev/null +++ b/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 diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..fab86c0 --- /dev/null +++ b/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 diff --git a/config/initializers/time_zone.rb b/config/initializers/time_zone.rb new file mode 100644 index 0000000..b5107cb --- /dev/null +++ b/config/initializers/time_zone.rb @@ -0,0 +1,2 @@ +# Sample usage of application config +Time.zone = Framework.app.config['default_timezone'] diff --git a/db/migrate/.keep b/db/migrate/.keep new file mode 100644 index 0000000..e69de29 diff --git a/lib/.keep b/lib/.keep new file mode 100644 index 0000000..e69de29 From 632d7d360a867d29765706f74a99ca8f4a4c63fc Mon Sep 17 00:00:00 2001 From: Sergei Zinin Date: Sun, 14 Dec 2014 14:08:11 +0700 Subject: [PATCH 2/4] Add README --- README.md | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6141e20..b223b3f 100644 --- a/README.md +++ b/README.md @@ -1 +1,96 @@ -This app utilizes Framework v0.0.7 and rocks MIT license. \ No newline at end of file +# The Task + +This task is to build the fake business model and predict revenue. + +------------------------------------------------------------------ + +# 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. + +## 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. + From 0ae76a1f3ed566138a43b3670f4b56f8994c3830 Mon Sep 17 00:00:00 2001 From: Sergei Zinin Date: Sun, 14 Dec 2014 14:23:02 +0700 Subject: [PATCH 3/4] gs --- README.md | 1 + app/models/client.rb | 3 +++ app/models/invoice.rb | 4 ++++ db/migrate/20141214070910_create_clients.rb | 15 +++++++++++++++ db/migrate/20141214071354_create_invoices.rb | 15 +++++++++++++++ 5 files changed, 38 insertions(+) create mode 100644 app/models/client.rb create mode 100644 app/models/invoice.rb create mode 100644 db/migrate/20141214070910_create_clients.rb create mode 100644 db/migrate/20141214071354_create_invoices.rb diff --git a/README.md b/README.md index b223b3f..570d6b7 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,7 @@ 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 diff --git a/app/models/client.rb b/app/models/client.rb new file mode 100644 index 0000000..780a508 --- /dev/null +++ b/app/models/client.rb @@ -0,0 +1,3 @@ +class Client < ActiveRecord::Base + has_many :invoices +end diff --git a/app/models/invoice.rb b/app/models/invoice.rb new file mode 100644 index 0000000..9bc7fb3 --- /dev/null +++ b/app/models/invoice.rb @@ -0,0 +1,4 @@ +class Invoice < ActiveRecord::Base + belongs_to :client +end + diff --git a/db/migrate/20141214070910_create_clients.rb b/db/migrate/20141214070910_create_clients.rb new file mode 100644 index 0000000..f9d3dad --- /dev/null +++ b/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 diff --git a/db/migrate/20141214071354_create_invoices.rb b/db/migrate/20141214071354_create_invoices.rb new file mode 100644 index 0000000..1f6ac70 --- /dev/null +++ b/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 From 00cb6b2dabfb480d08b486d0b332574efbde06a5 Mon Sep 17 00:00:00 2001 From: Sergei Zinin Date: Sun, 14 Dec 2014 14:23:17 +0700 Subject: [PATCH 4/4] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 570d6b7..f0a3ff4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # The Task -This task is to build the fake business model and predict revenue. +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. ------------------------------------------------------------------