/miner

Primary LanguageRuby

OnTheClock in the mine

Introduction

A Big Mining Company has asked you to develop a work time tracking solution for miners working for them underground. The app will be called OnTheClock and it will use Ruby On Rails.

Problem Statement

The miners enter their workplace through gates equipped with magnetic card readers. Each employee has a personal magnetic card with his or her identity. As soon as the employees enter the premises through the gates, their paid work time starts. When they leave the premises through the gates, their paid work time stops. The gates machinery calls the REST API in the OnTheClock app every time a person goes in or out. The called endpoint is POST /events and below is a sample of a .JSON that is sent:

{
	"employee_id": "999",
	"timestamp": 123456789,
	"kind": "in|out"
}

The employee_id is a unique identifier of an employee that caused this event. The timestamp is a UNIX timestamp holding event time. The kind is a string equal to either "in" or "out" and it indicates if it is an entry or a leave event. When the endpoint is called, the app should save the event in the SQLite database for further reporting.

The Payroll Department is interested in gate events because they need to know how much time each employee worked in a certain period of time. Therefore, the app needs to expose a GET /reports/{employee_id}/{from}/{to} endpoint, where the employee_id is a unique employee identifier of the employee, for whom the report should be generated. Whereas from and to are the string dates in the following format: YYYY-MM-DD, indicating the time span of the report. In response, the app should produce a report (based on the stored entry events) in the following format:

{
	"employee_id": "9999", 
	"from": "YYYY-MM-DD,
	"to": "YYYY-MM-DD", 
	"worktime_hrs": 999.99,
	"problematic_dates": ["YYYY-MM-DD", "YYYY-MM-DD", "YYYY-MM-DD"]
}

Where:

employee_id - the employee ID as per input params, from - the start date of the report as per input params, to - the end date of the report as per input params, worktime_hrs - the total number of hours, during which this employee worked in the requested period (a floating point number rounded to two decimal places), problematic_dates - it holds all dates on which there is an inconsistency in the entry/leave events. An inconsistency happens if there is an "in" event without a corresponding "out" event or if there is an "out" event without a corresponding "in" event.

Inconsistencies happen because sometimes the system may go down and it is unable to register any events or the employee may enter or leave the mine without pressing their card to the magnetic card reader. Consider the following events generated by one employee:

IN - 2019-01-01 08:00,
IN - 2019-01-02 08:00 -> no out event on the previous day (2019-01-01 is problematic),
OUT - 2019-01-02 16:00,
IN - 2019-01-03 08:00 -> no out event that day (2019-01-03 is problematic),
OUT - 2019-01-04 16:00 -> no in event that day (2019-01-04 is problematic).

The above sequence of events should provide the following problematic_dates: [2019-01-01, 2019-01-03, 2019-01-04].

When a date is considered problematic, it should not add any working hours to the report.

  1. Implement the two endpoints described above.
  2. There are all necessary classes and files created for you. You do not need to create any new files.
  3. Events should be stored and read using the Event Active Record model. The migration has already taken place. The duplicate events (as described above) should be stored as well and they should be handled during report generation.
  4. The report generation logic should be implemented in the ReportGenerator and Report classes.
  5. There is a minimal set of integration tests which only cover the basic cases. It is your job to discover all the edge cases and cover them with tests. At the end of the day, your solution will be verified thoroughly by our verification software.
  6. The endpoints should require all input params specified above. If params are missing or have invalid values, the endpoints should respond with the HTTP 400 bad request.
  7. There are TODOs in the code to assist you in the implementation.