ecom_core 1.2.28 → 1.2.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/concerns/ecom/core/filterable.rb +14 -0
  3. data/app/models/ecom/core/crew.rb +10 -1
  4. data/app/models/ecom/core/crew_time.rb +11 -3
  5. data/app/models/ecom/core/dimension_element.rb +22 -0
  6. data/app/models/ecom/core/job_card.rb +1 -1
  7. data/app/models/ecom/core/measurement_unit.rb +55 -0
  8. data/app/models/ecom/core/overtime_sheet.rb +15 -5
  9. data/app/models/ecom/core/plan.rb +18 -0
  10. data/app/models/ecom/core/schedule_setting.rb +8 -6
  11. data/app/models/ecom/core/schedule_unit.rb +1 -1
  12. data/app/models/ecom/core/takeoff.rb +10 -0
  13. data/app/models/ecom/core/takeoff_calculator.rb +115 -0
  14. data/app/models/ecom/core/task.rb +11 -0
  15. data/app/models/ecom/core/task_resource.rb +2 -0
  16. data/app/models/ecom/core/task_step.rb +85 -0
  17. data/app/models/ecom/core/task_step_dependency.rb +10 -0
  18. data/app/models/ecom/core/task_template.rb +92 -0
  19. data/app/models/ecom/core/work_order.rb +26 -0
  20. data/app/models/ecom/core/work_product.rb +1 -0
  21. data/db/migrate/20191119012027_create_ecom_core_takeoff_calculators.rb +11 -0
  22. data/db/migrate/20191119012030_create_ecom_core_task_templates.rb +7 -0
  23. data/db/migrate/20191202235434_create_ecom_core_work_products.rb +0 -1
  24. data/db/migrate/{20191225100054_create_ecom_core_crews.rb → 20191207103729_create_ecom_core_crews.rb} +3 -3
  25. data/db/migrate/20191207103730_create_ecom_core_plans.rb +12 -0
  26. data/db/migrate/20191207103731_create_ecom_core_work_orders.rb +23 -0
  27. data/db/migrate/20191207103735_create_ecom_core_tasks.rb +9 -1
  28. data/db/migrate/20200813165553_create_ecom_core_measurement_units.rb +14 -0
  29. data/db/migrate/20200814043632_create_ecom_core_takeoffs.rb +14 -0
  30. data/db/migrate/20200820123719_create_ecom_core_task_steps.rb +17 -0
  31. data/db/migrate/20200821130934_create_ecom_core_task_step_dependencies.rb +16 -0
  32. data/db/migrate/20200901134912_create_ecom_core_dimension_elements.rb +23 -0
  33. data/db/migrate/20200919085613_create_ecom_core_job_cards.rb +5 -4
  34. data/lib/ecom/core/version.rb +1 -1
  35. data/spec/factories/dimension_elements.rb +8 -0
  36. data/spec/factories/ecom/core/attendance_sheet_entries.rb +1 -1
  37. data/spec/factories/ecom/core/maintenance_statuses.rb +1 -1
  38. data/spec/factories/ecom/core/plans.rb +8 -0
  39. data/spec/factories/ecom/core/takeoff_calculators.rb +18 -0
  40. data/spec/factories/ecom/core/takeoffs.rb +6 -0
  41. data/spec/factories/ecom/core/task_step_dependencies.rb +6 -0
  42. data/spec/factories/ecom/core/task_steps.rb +8 -0
  43. data/spec/factories/ecom/core/task_templates.rb +6 -0
  44. data/spec/factories/ecom/core/work_orders.rb +10 -0
  45. data/spec/factories/ecom/core/work_products.rb +0 -1
  46. data/spec/factories/measurement_units.rb +10 -0
  47. metadata +42 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c60cc03ce91bb6a6fcda02c9d46c4f2a612db516dab13f6068e07b7410a236e8
4
- data.tar.gz: 128979b27e4fb0d111ea8c372cd3a17b312a473ad254b76b3f86ccdee9fd13d4
3
+ metadata.gz: a8a7e36cd705a1ecc9fd9211ee4e16695e93c02bdfec41122592a411f323914b
4
+ data.tar.gz: 51fea59e1ee52f090d450d667d27f45628f969aef8005caed0c56c401ae8781f
5
5
  SHA512:
6
- metadata.gz: ebb78acd53dfa40dfcb4a49a0bbbf0369c1282005b45dfa8af8909dd7ab095754d688408152eddce07b8dd91f193985a1b5f0a2b003d5746d7fd190283c31ee0
7
- data.tar.gz: 0327b3d3d94bc49ffd640d5557b678f62c75b75bf9f45f25d16e6016f8d31ed4e72f00a915653b1c734408bd18be3e29f3b89ad05a8337b798ec7f7ced71a489
6
+ metadata.gz: b12192fe563a2566ac3b8bdc3aeb74597e6a85a985e1d0d4542aa0e6443c8d21865b0161960f68b0a971d1087f42f69da0d35d91b2c22a05a000ae0cc535f209
7
+ data.tar.gz: 68647fa87b9ad37c2da425386c04304c91436cf079fd077d56d1917514f381ccdede99b0fe85b07701fd228cb7c01126f4a8edd5eb970e05f1fa6d140acce359
@@ -0,0 +1,14 @@
1
+ module Ecom
2
+ module Core
3
+ module Filterable
4
+ extend ActiveSupport::Concern
5
+
6
+ module ClassMethods
7
+ def filter(filtering_params)
8
+ results = where(nil)
9
+ results.public_send('filter_by_condition', filtering_params) if filtering_params.present?
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -10,9 +10,11 @@ module Ecom
10
10
  before_save :set_employment_date,
11
11
  if: proc { |c| c.employment_date.nil? }
12
12
 
13
+ after_save :set_employee_id
14
+
13
15
  belongs_to :crew_type
14
16
 
15
- validates :name, :address, :qualification, :employment, :wage, :wage_in_words, presence: true
17
+ validates :name, :address, :qualification, :employment, :wage, :guarantor_name, :guarantor_phone, presence: true
16
18
  validates :employment, inclusion: EMPLOYMENT_TYPES
17
19
 
18
20
  has_many :project_crews
@@ -25,6 +27,13 @@ module Ecom
25
27
  def set_employment_date
26
28
  self.employment_date = Date.today
27
29
  end
30
+
31
+ def set_employee_id
32
+ company = Ecom::Core::Company.first
33
+ date = employment_date.to_s[0..3]
34
+ company_name = company ? company.name : ''
35
+ self.employee_id = "#{company_name}/#{employment}/#{date}/#{id}"
36
+ end
28
37
  end
29
38
  end
30
39
  end
@@ -12,7 +12,7 @@ module Ecom
12
12
  has_one :revision, class_name: 'Ecom::Core::CrewTime', foreign_key: :revision_to_id
13
13
 
14
14
  validates :checkin_time, presence: true, if: :checkout_time
15
- validate :checkout_is_greater_than_checkin
15
+ validate :time_range_validation, :total_time_validation
16
16
 
17
17
  scope :by_attendance, lambda { |id|
18
18
  joins(:attendance_sheet_entry).where(ecom_core_attendance_sheet_entries: { attendance_sheet_id: id })
@@ -20,14 +20,22 @@ module Ecom
20
20
  scope :revised, ->(revised) { where(revised: revised) }
21
21
 
22
22
  before_save :calculate_hours
23
- after_save :calculate_total
23
+ after_save :compute_total_for_entry # :calculate_total
24
24
 
25
- def checkout_is_greater_than_checkin
25
+ def time_range_validation
26
26
  return unless checkin_time && checkout_time && checkout_time <= checkin_time
27
27
 
28
28
  errors.add(:checkout_time, "can't be less than checkin time.")
29
29
  end
30
30
 
31
+ def total_time_validation
32
+ return if checkout_time.nil? || checkin_time.nil?
33
+
34
+ return unless attendance_sheet_entry.total_hours + compute_hours > 8
35
+
36
+ errors.add(:attendance_sheet_entry, 'has more than 8 hours')
37
+ end
38
+
31
39
  def calculate_hours
32
40
  self.hours = if checkout_time.nil? || checkin_time.nil?
33
41
  0
@@ -0,0 +1,22 @@
1
+ module Ecom
2
+ module Core
3
+ class DimensionElement < ApplicationRecord
4
+ LENGTH = 'Length'.freeze
5
+ WIDTH = 'Width'.freeze
6
+ HEIGHT = 'Height'.freeze
7
+ RADIUS = 'Radius'.freeze
8
+ DIAMETER = 'Diameter'.freeze
9
+ DIMENSION_ELEMENT_NAMES = %w[LENGTH WIDTH HEIGHT RADIUS DIAMETER].freeze
10
+
11
+ validates :work_product_id, :work_product, :measurement_unit_id, :measurement_unit,
12
+ :amount, :dimension_element_name, presence: true
13
+
14
+ validates :dimension_element_name, inclusion: DIMENSION_ELEMENT_NAMES
15
+
16
+ validates :amount, numericality: { greater_than: 0 }
17
+
18
+ belongs_to :work_product
19
+ belongs_to :measurement_unit
20
+ end
21
+ end
22
+ end
@@ -13,4 +13,4 @@ module Ecom
13
13
  validates :code, presence: true, uniqueness: true
14
14
  end
15
15
  end
16
- end
16
+ end
@@ -0,0 +1,55 @@
1
+ module Ecom
2
+ module Core
3
+ class MeasurementUnit < ApplicationRecord
4
+ METRIC = 'Metric'.freeze
5
+ IMPERIAL = 'Imperial'.freeze
6
+ SYSTEM_OF_MEASURMENT = [METRIC, IMPERIAL].freeze
7
+
8
+ # commonly used physical quantities in construction
9
+ LENGTH = 'Length'.freeze
10
+ MASS = 'Mass'.freeze
11
+ TIME = 'Time'.freeze
12
+ CURRENT = 'Current'.freeze
13
+ TEMPRATURE = 'Temprature'.freeze
14
+
15
+ AREA = 'Area'.freeze
16
+ VOLUME = 'Volume'.freeze
17
+ ENERGY = 'Energy'.freeze
18
+ DENSITY = 'DENSITY'.freeze
19
+
20
+ PHYSICAL_QUANTITIES = [LENGTH, MASS, TIME, CURRENT, TEMPRATURE, AREA, VOLUME, ENERGY, DENSITY].freeze
21
+
22
+ validates :name, :abbrivation, :physical_quantity,
23
+ :conversion_factor, :system_of_measurement, presence: true
24
+
25
+ validates :is_si_unit, inclusion: { in: [true, false] }
26
+
27
+ validates :system_of_measurement, inclusion: SYSTEM_OF_MEASURMENT
28
+ validates :physical_quantity, inclusion: PHYSICAL_QUANTITIES
29
+
30
+ validate :si_unit_with_conversion_factor
31
+ validate :si_unit_system_of_measurement_and_physical_quantity
32
+
33
+ def si_unit_with_conversion_factor
34
+ if is_si_unit && conversion_factor != 1
35
+ errors.add(:base, 'Conversion factor for an SI unit has to be 1')
36
+ elsif !is_si_unit && conversion_factor == 1
37
+ errors.add(:base, 'Only SI units can have a conversion factor 1')
38
+ end
39
+ end
40
+
41
+ # scope si unit with system of measurement and physical quantity
42
+ def si_unit_system_of_measurement_and_physical_quantity
43
+ return if system_of_measurement.nil? || physical_quantity.nil?
44
+
45
+ existing_record = MeasurementUnit
46
+ .where(system_of_measurement: system_of_measurement,
47
+ physical_quantity: physical_quantity, is_si_unit: true).first
48
+ return unless (new_record? && existing_record.present?) || (persisted? && existing_record != self)
49
+
50
+ errors.add(:is_si_unit,
51
+ 'There exist an si unit of measurement for the given physical quantity and system of measurement')
52
+ end
53
+ end
54
+ end
55
+ end
@@ -13,19 +13,29 @@ module Ecom
13
13
  scope :by_date, ->(date) { where(date: date) }
14
14
  scope :by_status, ->(status) { where(status: status) }
15
15
  scope :by_date_between, ->(from, to) { where('date BETWEEN ? AND ?', from, to) }
16
- scope :open, ->(id) { where(status: StatusConstants::OPEN, project_id: id) }
17
- scope :submitted, ->(id) { where(status: StatusConstants::SUBMITTED, project_id: id) }
16
+ # scope :open, ->(id) { where(status: StatusConstants::OPEN, project_id: id) }
17
+ # scope :submitted, ->(id) { where(status: StatusConstants::SUBMITTED, project_id: id) }
18
18
 
19
19
  def self.open_exists?(project_id)
20
- OvertimeSheet.open(project_id).exists?
20
+ OvertimeSheet
21
+ .by_project(project_id)
22
+ .by_status(StatusConstants::OPEN)
23
+ .exists?
21
24
  end
22
25
 
23
26
  def self.open_for_date_exists?(date, project_id)
24
- OvertimeSheet.open(project_id).where(date: date).exists?
27
+ OvertimeSheet
28
+ .by_project(project_id)
29
+ .by_status(StatusConstants::OPEN)
30
+ .by_date(date)
31
+ .exists?
25
32
  end
26
33
 
27
34
  def self.exists_for_date?(date, project_id)
28
- OvertimeSheet.by_project(project_id).by_date(date).exists?
35
+ OvertimeSheet
36
+ .by_project(project_id)
37
+ .by_date(date)
38
+ .exists?
29
39
  end
30
40
 
31
41
  # Overtime sheet should be created using the
@@ -0,0 +1,18 @@
1
+ module Ecom
2
+ module Core
3
+ class Plan < ApplicationRecord
4
+ NEW = 'New'.freeze
5
+ READY_TO_START = 'Ready to start'.freeze
6
+ IN_PROGRESS = 'In Progress'.freeze
7
+ COMPLETED = 'Completed'.freeze
8
+
9
+ STATUSES = [NEW, READY_TO_START, IN_PROGRESS, COMPLETED].freeze
10
+
11
+ validates :name, :start_date, :end_date, :status, presence: true
12
+
13
+ validates :status, presence: true, inclusion: STATUSES
14
+
15
+ has_many :tasks
16
+ end
17
+ end
18
+ end
@@ -1,9 +1,11 @@
1
- module Ecom::Core
2
- class ScheduleSetting < ApplicationRecord
3
- belongs_to :equipment
4
- belongs_to :maintenance_type
5
- belongs_to :schedule_unit
1
+ module Ecom
2
+ module Core
3
+ class ScheduleSetting < ApplicationRecord
4
+ belongs_to :equipment
5
+ belongs_to :maintenance_type
6
+ belongs_to :schedule_unit
6
7
 
7
- validates :value, presence: true
8
+ validates :value, presence: true
9
+ end
8
10
  end
9
11
  end
@@ -3,4 +3,4 @@ module Ecom
3
3
  class ScheduleUnit < Lookup
4
4
  end
5
5
  end
6
- end
6
+ end
@@ -0,0 +1,10 @@
1
+ module Ecom
2
+ module Core
3
+ class Takeoff < ApplicationRecord
4
+ validates :task_id, :takeoff_quantity, :task, presence: true
5
+ validates :takeoff_quantity, numericality: { greater_than: 0 }
6
+
7
+ belongs_to :task
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,115 @@
1
+ module Ecom
2
+ module Core
3
+ class TakeoffCalculator < ApplicationRecord
4
+ INPUT_PARAMETERS_SCHEMA = {
5
+ 'type' => 'object',
6
+ 'required' => %w[name label input_type],
7
+ 'additionalProperties' => false,
8
+ 'properties' => {
9
+ 'name' => { 'type' => 'string' },
10
+ 'label' => { 'type' => 'string' },
11
+ 'input_type' => {
12
+ 'type' => 'string',
13
+ 'enum' => %w[string number measurement enum]
14
+ }
15
+ },
16
+ "patternProperties": {
17
+ "enum_values": {
18
+ 'type' => 'array'
19
+ },
20
+ "default_value": {
21
+ 'type' => 'object',
22
+ 'required' => %w[value],
23
+ 'properties' => {
24
+ 'value' => { 'type' => 'string' }
25
+ },
26
+ "patternProperties": {
27
+ "measurement_unit_id": { 'type' => 'integer' }
28
+ }
29
+ },
30
+ "validation": {
31
+ 'type' => 'object',
32
+ 'required' => %w[required],
33
+ 'properties' => {
34
+ 'required' => { 'type' => 'boolean' }
35
+ },
36
+ "patternProperties": {
37
+ "minimum": { 'type' => 'number' },
38
+ "maximum": { 'type' => 'number' }
39
+ }
40
+ }
41
+ }
42
+ }.freeze
43
+
44
+ REBAR_TAKEOFF_CALCULATOR = 'Rebar Takeoff Calculator'.freeze
45
+ FORMWORK_TAKEOFF_CALCULATOR = 'Formwork Takeoff Calculator'.freeze
46
+ CONCRETE_POURING_TAKEOFF_CALCULATOR =
47
+ 'Concrete Pouring Takeoff Calculator'.freeze
48
+
49
+ TAKEOFF_CALCULATOR_NAMES =
50
+ [
51
+ REBAR_TAKEOFF_CALCULATOR,
52
+ FORMWORK_TAKEOFF_CALCULATOR,
53
+ CONCRETE_POURING_TAKEOFF_CALCULATOR
54
+ ].freeze
55
+
56
+ validates :name, :input_parameters, presence: true
57
+ validates :name, inclusion: TAKEOFF_CALCULATOR_NAMES
58
+
59
+ validates :name, uniqueness: true
60
+
61
+ validate :input_parameters_schema
62
+ validate :measurement_unit_id_in_input_parameters
63
+ validate :enum_in_input_parameters
64
+
65
+ def input_parameters_schema
66
+ return if input_parameters.nil?
67
+
68
+ errors.add(:input_parameters, 'There has to be one or more input parameters') if input_parameters.count.zero?
69
+
70
+ validation_errors = JSON::Validator.fully_validate(INPUT_PARAMETERS_SCHEMA,
71
+ input_parameters, strict: true,
72
+ list: true, clear_cache: true)
73
+
74
+ errors.add(:input_parameters, validation_errors) unless validation_errors.empty?
75
+ end
76
+
77
+ def measurement_unit_id_in_input_parameters
78
+ return if input_parameters.nil?
79
+
80
+ input_parameters.each do |input_parameter|
81
+ next unless input_parameter['input_type'] == 'measurement' && !input_parameter['default_value'].nil?
82
+
83
+ if input_parameter['default_value']['measurement_unit_id'].nil?
84
+ errors.add(:base, 'measurement_unit_id is required')
85
+ next
86
+ end
87
+
88
+ measurement_unit_id = input_parameter['default_value']['measurement_unit_id']
89
+ measurement_unit = Ecom::Core::MeasurementUnit.find_by(id: measurement_unit_id)
90
+
91
+ errors.add(:base, "measurement unit with id #{measurement_unit_id} does not exist") if measurement_unit.nil?
92
+ end
93
+ end
94
+
95
+ def enum_in_input_parameters
96
+ return if input_parameters.nil?
97
+
98
+ input_parameters.each do |input_parameter|
99
+ next if input_parameter['input_type'] != 'enum'
100
+
101
+ if input_parameter['enum_values'].nil?
102
+ errors.add(:base, 'enum_values are requiered if the input_type is enum')
103
+ next
104
+ end
105
+
106
+ next unless !input_parameter['enum_values'].nil? &&
107
+ input_parameter['enum_values'].class == Array &&
108
+ input_parameter['enum_values'].count.zero?
109
+
110
+ errors.add(:base, 'Provide at least one enum value')
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
@@ -8,11 +8,18 @@ module Ecom
8
8
  belongs_to :work_product
9
9
  belongs_to :task_template
10
10
  belongs_to :work_package, optional: true
11
+ belongs_to :work_order, optional: true
12
+ belongs_to :plan, optional: true
11
13
  belongs_to :performer, class_name: 'Ecom::Core::User', optional: true
12
14
  belongs_to :approver, class_name: 'Ecom::Core::User', optional: true
13
15
  belongs_to :supervisor, class_name: 'Ecom::Core::User', optional: true
14
16
  belongs_to :quality_controller, class_name: 'Ecom::Core::User', optional: true
15
17
 
18
+ has_many :task_steps
19
+ has_many :task_resources
20
+ has_one :takeoff
21
+
22
+ validates_with DateRangeValidator
16
23
  validates :code, :name, :status, :percent_completed, presence: true
17
24
  validates_numericality_of :percent_completed,
18
25
  only_integer: true,
@@ -21,8 +28,12 @@ module Ecom
21
28
 
22
29
  scope :by_status, ->(status) { where(status: status) }
23
30
 
31
+ # State: planned -> The task has be planned for execution
32
+ # State: ready_to_start -> All resources for the task has been set and is ready to start
24
33
  aasm column: 'status' do
25
34
  state :new, initial: true
35
+ state :planned
36
+ state :ready_to_start
26
37
  state :in_progress
27
38
  state :submitted
28
39
  state :under_review
@@ -1,6 +1,8 @@
1
1
  module Ecom
2
2
  module Core
3
3
  class TaskResource < ApplicationRecord
4
+ validates :task_id, :task, :resource_type_id, :resource_type, presence: true
5
+
4
6
  belongs_to :task
5
7
  belongs_to :resource_type
6
8
 
@@ -0,0 +1,85 @@
1
+ module Ecom
2
+ module Core
3
+ class TaskStep < ApplicationRecord
4
+ include Filterable
5
+
6
+ before_save :update_task_progress
7
+
8
+ scope :filter_by_condition, ->(condition) { where(condition) }
9
+
10
+ validates :name, :total_contribution_percentage_to_task, presence: true
11
+ validates_with DateRangeValidator
12
+ validate :date_range_validator
13
+ validates_numericality_of :total_contribution_percentage_to_task,
14
+ greater_than: 0,
15
+ less_than_or_equal_to: 100
16
+
17
+ validate :task_step_percentage_validator, on: :create
18
+
19
+ validate :task_step_in_task_template_inclusion_validator
20
+
21
+ belongs_to :task
22
+ has_many :dependent_task_steps,
23
+ class_name: 'Ecom::Core::TaskStepDependency', foreign_key: 'dependent_task_step_id'
24
+ has_many :dependee_task_steps,
25
+ class_name: 'Ecom::Core::TaskStepDependency', foreign_key: 'dependee_task_step_id'
26
+
27
+ def date_range_validator
28
+ task_ = Ecom::Core::Task.find_by(id: task_id)
29
+
30
+ return if task_.nil?
31
+
32
+ if !start_date.nil? && start_date < task_.start_date
33
+ errors.add(:start_date, "The task steps start date can not be before the task's start date")
34
+ end
35
+
36
+ return unless !end_date.nil? && end_date > task_.end_date
37
+
38
+ errors.add(:end_date, "The task steps end date can not be after the task's end date")
39
+ end
40
+
41
+ def task_step_percentage_validator
42
+ return if task_id.nil?
43
+
44
+ task = Ecom::Core::Task.find_by(id: task_id)
45
+
46
+ return if task.nil?
47
+
48
+ total_contribution_of_all_task_steps = task.task_steps.sum(:total_contribution_percentage_to_task)
49
+
50
+ max_total_contribution = 100 - total_contribution_of_all_task_steps
51
+ return unless total_contribution_percentage_to_task > max_total_contribution
52
+
53
+ errors
54
+ .add(:total_contribution_of_all_task_steps,
55
+ "The maximum that this task step can contribute to the total task is #{max_total_contribution}")
56
+ end
57
+
58
+ def update_task_progress
59
+ return unless completed_changed? && completed == true
60
+
61
+ # update the task progress
62
+ task = self.task
63
+ percent_completed = task.percent_completed
64
+ task.percent_completed = (percent_completed + total_contribution_percentage_to_task).to_i
65
+ task.save
66
+ end
67
+
68
+ def task_step_in_task_template_inclusion_validator
69
+ return if task_id.nil?
70
+
71
+ task = Ecom::Core::Task.find_by(id: task_id)
72
+
73
+ return if task.nil?
74
+
75
+ task_template = task.task_template
76
+
77
+ return unless task_template.task_steps.nil?
78
+
79
+ errors.add(:base,
80
+ 'Task steps are not defined for the given task in the
81
+ task template, please first define the task steps in the task template.')
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,10 @@
1
+ module Ecom
2
+ module Core
3
+ class TaskStepDependency < ApplicationRecord
4
+ validates :dependent_task_step_id, :dependee_task_step_id, presence: true
5
+
6
+ belongs_to :dependent_task_step, class_name: 'Ecom::Core::TaskStep'
7
+ belongs_to :dependee_task_step, class_name: 'Ecom::Core::TaskStep'
8
+ end
9
+ end
10
+ end
@@ -1,16 +1,58 @@
1
+ require 'json-schema'
1
2
  module Ecom
2
3
  module Core
3
4
  class TaskTemplate < ApplicationRecord
5
+ TASK_STEP_SCHEMA = {
6
+ 'type' => 'object',
7
+ 'required' => %w[name total_contribution_percentage_to_task],
8
+ 'additionalProperties' => false,
9
+ 'properties' => {
10
+ 'name' => { 'type' => 'string' },
11
+ 'total_contribution_percentage_to_task' => {
12
+ 'type' => 'integer',
13
+ 'minimum' => 1,
14
+ 'maximum' => 100
15
+ }
16
+ }
17
+ }.freeze
18
+
19
+ # here the json schema has a bug ( including all properties as required)
20
+ # and because task_step_name is required on a condition ( only if the
21
+ # milestone is after a task step ), we can solve this with a workaround
22
+ # by specifying task_step_name in patternProperties.
23
+ MILESTONE_SCHEMA = {
24
+ 'type' => 'object',
25
+ 'required' => %w[name is_after_task_step],
26
+ 'additionalProperties' => false,
27
+ 'properties' => {
28
+ 'name' => { 'type' => 'string' },
29
+ 'is_after_task_step' => {
30
+ 'type' => 'boolean'
31
+ }
32
+ },
33
+ "patternProperties": {
34
+ "task_step_name": {
35
+ 'type' => 'string'
36
+ }
37
+ }
38
+ }.freeze
39
+
4
40
  has_ancestry
5
41
 
6
42
  belongs_to :task_template_type
7
43
  has_and_belongs_to_many :work_product_templates, join_table: 'ecom_core_task_templates_work_product_templates'
8
44
  has_and_belongs_to_many :resource_types, join_table: 'ecom_core_task_templates_resource_types'
45
+ belongs_to :takeoff_calculator, optional: true
9
46
 
10
47
  validates :name, :code, presence: true
11
48
  validates :code, uniqueness: true
12
49
  delegate(:name, to: :task_template_type, prefix: true)
13
50
 
51
+ validate :task_steps_schema_validator
52
+ validate :milestones_schema_validator
53
+ validate :validate_sum_of_task_step_contribution
54
+ validate :validate_milestone_task_step_association
55
+
14
56
  def full_name
15
57
  parent_name = parent&.name
16
58
  return name unless parent_name
@@ -29,6 +71,56 @@ module Ecom
29
71
  def equipment_types
30
72
  resource_types.where(type: 'Ecom::Core::EquipmentType')
31
73
  end
74
+
75
+ def task_steps_schema_validator
76
+ return if task_steps.nil?
77
+
78
+ validation_errors = JSON::Validator.fully_validate(TASK_STEP_SCHEMA,
79
+ task_steps, strict: true,
80
+ list: true, clear_cache: true)
81
+
82
+ errors.add(:task_steps, validation_errors) unless validation_errors.empty?
83
+ end
84
+
85
+ def milestones_schema_validator
86
+ return if milestones.nil?
87
+
88
+ validation_errors = JSON::Validator.fully_validate(MILESTONE_SCHEMA,
89
+ milestones, strict: true,
90
+ list: true, clear_cache: true)
91
+
92
+ errors.add(:milestones, validation_errors) unless validation_errors.empty?
93
+ end
94
+
95
+ def validate_sum_of_task_step_contribution
96
+ return if task_steps.nil?
97
+
98
+ filtered_task_steps = task_steps.select { |task_step| task_step['total_contribution_percentage_to_task'] }
99
+
100
+ sum_of_task_step_contribution =
101
+ filtered_task_steps.sum { |task_step| task_step['total_contribution_percentage_to_task'] }
102
+
103
+ errors.add(:task_steps, 'Sum of task step contributions has to be 100') if sum_of_task_step_contribution != 100
104
+ end
105
+
106
+ def validate_milestone_task_step_association
107
+ return if milestones.nil?
108
+
109
+ task_step_names = task_steps&.map { |task_step| task_step['name'] }
110
+
111
+ milestones_associated_with_task_step = milestones.select { |milestone| milestone['is_after_task_step'] }
112
+
113
+ milestones_associated_with_task_step.each do |milestone|
114
+ if milestone['task_step_name'].nil?
115
+ errors.add(:milestones, 'if the milestone is after a task step, please specify the task step name')
116
+ next
117
+ end
118
+
119
+ unless task_step_names.include? milestone['task_step_name']
120
+ errors.add(:milestone, 'task step for the given milestone does not exist in list of task steps')
121
+ end
122
+ end
123
+ end
32
124
  end
33
125
  end
34
126
  end
@@ -0,0 +1,26 @@
1
+ module Ecom
2
+ module Core
3
+ class WorkOrder < ApplicationRecord
4
+ before_save :add_reference_number
5
+
6
+ NEW = 'New'.freeze
7
+ IN_PROGRESS = 'In Progress'.freeze
8
+ COMPLETED = 'Completed'.freeze
9
+
10
+ STATUSES = [NEW, IN_PROGRESS, COMPLETED].freeze
11
+
12
+ validates :name, :assigned_to_id, :generated_by_id, :status,
13
+ :start_date, :end_date, presence: true
14
+
15
+ validates :status, presence: true, inclusion: STATUSES
16
+
17
+ belongs_to :assigned_to, class_name: 'Ecom::Core::Crew'
18
+ belongs_to :generated_by, class_name: 'Ecom::Core::User'
19
+ has_many :tasks
20
+
21
+ def add_reference_number
22
+ self.reference_number = "WO-#{(Time.now.to_f * 1000).to_i}"
23
+ end
24
+ end
25
+ end
26
+ end
@@ -30,6 +30,7 @@ module Ecom
30
30
  belongs_to :supervisor, class_name: 'Ecom::Core::User', optional: true
31
31
  belongs_to :quality_controller, class_name: 'Ecom::Core::User', optional: true
32
32
  has_many :tasks
33
+ has_many :dimension_elements
33
34
 
34
35
  validates :name, :design_reference_no, :status, :percent_completed, presence: true
35
36
  validates :design_reference_no, uniqueness: { scope: :project_id }
@@ -0,0 +1,11 @@
1
+ class CreateEcomCoreTakeoffCalculators < ActiveRecord::Migration[6.0]
2
+ def change
3
+ create_table :ecom_core_takeoff_calculators do |t|
4
+ t.string :name, unique: true
5
+ t.boolean :is_custom_calculator, null: false, default: false
6
+ t.jsonb :input_parameters
7
+
8
+ t.timestamps
9
+ end
10
+ end
11
+ end
@@ -8,9 +8,16 @@ class CreateEcomCoreTaskTemplates < ActiveRecord::Migration[6.0]
8
8
  null: false,
9
9
  index: { name: 'tt_on_ttt_indx' },
10
10
  foreign_key: { to_table: :ecom_core_task_template_types }
11
+ t.references :takeoff_calculator,
12
+ null: true,
13
+ index: { name: 'tt_on_tc_indx' },
14
+ foreign_key: { to_table: :ecom_core_takeoff_calculators }
11
15
  t.string :ancestry, index: true
12
16
  t.boolean :has_takeoff_fields, null:false, default: false
13
17
  t.jsonb :fields
18
+ t.jsonb :takeoff_fields
19
+ t.jsonb :task_steps
20
+ t.jsonb :milestones
14
21
 
15
22
  t.timestamps
16
23
  end
@@ -4,7 +4,6 @@ class CreateEcomCoreWorkProducts < ActiveRecord::Migration[6.0]
4
4
  t.string :name, null: false
5
5
  t.string :description
6
6
  t.string :design_reference_no, unique: true
7
- t.json :dimension
8
7
  t.references :product_group,
9
8
  null: true,
10
9
  index: { name: 'wp_on_pg_indx' },
@@ -9,12 +9,12 @@ class CreateEcomCoreCrews < ActiveRecord::Migration[6.0]
9
9
  t.string :qualification, null: false
10
10
  t.string :employment, null: false
11
11
  t.float :wage, null: false
12
- t.string :wage_in_words, null: false
12
+ t.string :wage_in_words
13
13
  t.date :employment_date
14
14
  t.boolean :sub_contracted, null: false, default: false
15
15
  t.string :photo
16
- t.string :guarantor_name
17
- t.string :guarantor_phone
16
+ t.string :guarantor_name, null: false
17
+ t.string :guarantor_phone, null: false
18
18
  t.boolean :active, null: false, default: true
19
19
  t.references :crew_type,
20
20
  null: false,
@@ -0,0 +1,12 @@
1
+ class CreateEcomCorePlans < ActiveRecord::Migration[6.0]
2
+ def change
3
+ create_table :ecom_core_plans do |t|
4
+ t.string :name, null: false
5
+ t.date :start_date, null: false
6
+ t.date :end_date, null: false
7
+ t.string :status, null: false, default: 'New'
8
+
9
+ t.timestamps
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,23 @@
1
+ class CreateEcomCoreWorkOrders < ActiveRecord::Migration[6.0]
2
+ def change
3
+ create_table :ecom_core_work_orders do |t|
4
+ t.string :name
5
+ t.string :reference_number
6
+ t.references :assigned_to,
7
+ null: false,
8
+ index: { name: 'wo_on_at_indx' },
9
+ foreign_key: { to_table: :ecom_core_crews }
10
+
11
+ t.references :generated_by,
12
+ null: false,
13
+ index: { name: 'wo_on_gb_indx' },
14
+ foreign_key: { to_table: :ecom_core_users }
15
+
16
+ t.date :start_date, null: false
17
+ t.date :end_date, null: false
18
+ t.string :status, null: false, default: :new
19
+
20
+ t.timestamps
21
+ end
22
+ end
23
+ end
@@ -12,8 +12,16 @@ class CreateEcomCoreTasks < ActiveRecord::Migration[6.0]
12
12
  t.string :remark
13
13
  t.references :work_package,
14
14
  null: true,
15
- index: { name: 'wp_on_wp_indx' },
15
+ index: { name: 'tasks_on_work_package_indx' },
16
16
  foreign_key: { to_table: :ecom_core_work_packages }
17
+ t.references :work_order,
18
+ null: true,
19
+ index: { name: 'tasks_on_wo_indx' },
20
+ foreign_key: { to_table: :ecom_core_work_orders }
21
+ t.references :plan,
22
+ null: true,
23
+ index: { name: 'tasks_on_plan_indx' },
24
+ foreign_key: { to_table: :ecom_core_plans }
17
25
  t.references :performer,
18
26
  null: true,
19
27
  index: { name: 'tasks_on_performer_indx' },
@@ -0,0 +1,14 @@
1
+ class CreateEcomCoreMeasurementUnits < ActiveRecord::Migration[6.0]
2
+ def change
3
+ create_table :ecom_core_measurement_units do |t|
4
+ t.string :name, null: false
5
+ t.string :abbrivation, null: false
6
+ t.string :physical_quantity, null: false
7
+ t.boolean :is_si_unit, null: false, default: false
8
+ t.float :conversion_factor, null: false
9
+ t.string :system_of_measurement, null: false
10
+
11
+ t.timestamps
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ class CreateEcomCoreTakeoffs < ActiveRecord::Migration[6.0]
2
+ def change
3
+ create_table :ecom_core_takeoffs do |t|
4
+ t.references :task,
5
+ null: false,
6
+ index: { name: 'takeoff_on_task_indx' },
7
+ foreign_key: { to_table: :ecom_core_tasks }
8
+
9
+ t.float :takeoff_quantity, null: false
10
+
11
+ t.timestamps
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,17 @@
1
+ class CreateEcomCoreTaskSteps < ActiveRecord::Migration[6.0]
2
+ def change
3
+ create_table :ecom_core_task_steps do |t|
4
+ t.references :task,
5
+ null: false,
6
+ index: { name: 'ts_on_task_indx' },
7
+ foreign_key: { to_table: :ecom_core_tasks }
8
+ t.string :name, null: false
9
+ t.date :start_date
10
+ t.date :end_date
11
+ t.float :total_contribution_percentage_to_task, null: false
12
+ t.boolean :completed, null: false, default: false
13
+
14
+ t.timestamps
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,16 @@
1
+ class CreateEcomCoreTaskStepDependencies < ActiveRecord::Migration[6.0]
2
+ def change
3
+ create_table :ecom_core_task_step_dependencies do |t|
4
+ t.references :dependent_task_step,
5
+ null: false,
6
+ index: { name: 'tsd_on_dts_indx' },
7
+ foreign_key: { to_table: :ecom_core_task_steps }
8
+
9
+ t.references :dependee_task_step,
10
+ null: false,
11
+ index: { name: 'tsd_on_dependee_ts_indx' },
12
+ foreign_key: { to_table: :ecom_core_task_steps }
13
+ t.timestamps
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,23 @@
1
+ class CreateEcomCoreDimensionElements < ActiveRecord::Migration[6.0]
2
+ def change
3
+ create_table :ecom_core_dimension_elements do |t|
4
+
5
+ t.references :work_product,
6
+ null: false,
7
+ index: { name: 'dimension_on_wp_indx' },
8
+ foreign_key: { to_table: :ecom_core_work_products }
9
+
10
+ t.references :measurement_unit,
11
+ null: false,
12
+ index: { name: 'dimension_on_mu_indx' },
13
+ foreign_key: { to_table: :ecom_core_measurement_units }
14
+
15
+ t.string :dimension_element_name, null: false
16
+ t.float :amount
17
+
18
+ t.timestamps
19
+ end
20
+
21
+ add_index :ecom_core_dimension_elements, [:work_product_id, :dimension_element_name], unique: true, name: 'de_on_wp_and_den'
22
+ end
23
+ end
@@ -9,6 +9,7 @@ class CreateEcomCoreJobCards < ActiveRecord::Migration[6.0]
9
9
  t.boolean :approved, null: false, default: false
10
10
  t.boolean :checkin_confirmed, null: false, default: false
11
11
  t.boolean :checkout_confirmed, null: false, default: false
12
+ t.boolean :costs_approved, null: false, default: false
12
13
  t.references :maintenance_service_order,
13
14
  null: false,
14
15
  index: { name: 'jc_on_mso_indx' },
@@ -18,11 +19,11 @@ class CreateEcomCoreJobCards < ActiveRecord::Migration[6.0]
18
19
  index: { name: 'jc_on_sp_indx' },
19
20
  foreign_key: { to_table: :ecom_core_equipment_locations }
20
21
  t.references :checkout_by,
21
- null: false,
22
+ null: true,
22
23
  index: { name: 'jc_on_cb_indx' },
23
24
  foreign_key: { to_table: :ecom_core_users }
24
25
  t.references :checkout_to,
25
- null: false,
26
+ null: true,
26
27
  index: { name: 'jc_on_ct_indx' },
27
28
  foreign_key: { to_table: :ecom_core_equipment_locations }
28
29
  t.references :maintenance_status,
@@ -30,11 +31,11 @@ class CreateEcomCoreJobCards < ActiveRecord::Migration[6.0]
30
31
  index: { name: 'jc_on_ms_indx' },
31
32
  foreign_key: { to_table: :ecom_core_lookups }
32
33
  t.references :checkin_by,
33
- null: false,
34
+ null: true,
34
35
  index: { name: 'jc_on_cib_indx' },
35
36
  foreign_key: { to_table: :ecom_core_users }
36
37
  t.references :checkin_to,
37
- null: false,
38
+ null: true,
38
39
  index: { name: 'jc_on_cit_indx' },
39
40
  foreign_key: { to_table: :ecom_core_equipment_locations }
40
41
  t.references :prepared_by,
@@ -1,5 +1,5 @@
1
1
  module Ecom
2
2
  module Core
3
- VERSION = '1.2.28'.freeze
3
+ VERSION = '1.2.33'.freeze
4
4
  end
5
5
  end
@@ -0,0 +1,8 @@
1
+ FactoryBot.define do
2
+ factory :dimension_element, class: Ecom::Core::DimensionElement do
3
+ association :work_product
4
+ association :measurement_unit
5
+ amount { 5 }
6
+ dimension_element_name { Ecom::Core::DimensionElement::DIMENSION_ELEMENT_NAMES.sample }
7
+ end
8
+ end
@@ -2,6 +2,6 @@ FactoryBot.define do
2
2
  factory :attendance_sheet_entry, class: Ecom::Core::AttendanceSheetEntry do
3
3
  association :attendance_sheet
4
4
  association :crew
5
- total_hours { FFaker::Random.rand(0..8) }
5
+ total_hours { 0 }
6
6
  end
7
7
  end
@@ -1,5 +1,5 @@
1
1
  FactoryBot.define do
2
2
  factory :maintenance_status, class: Ecom::Core::MaintenanceStatus, parent: :lookup do
3
- type { 'Ecom::Core::MaintenanceStatus'}
3
+ type { 'Ecom::Core::MaintenanceStatus' }
4
4
  end
5
5
  end
@@ -0,0 +1,8 @@
1
+ FactoryBot.define do
2
+ factory :plan, class: Ecom::Core::Plan do
3
+ name { FFaker::Name.name }
4
+ start_date { Time.now }
5
+ end_date { (Time.now + 1.day).to_s }
6
+ status { Ecom::Core::Plan::STATUSES.sample }
7
+ end
8
+ end
@@ -0,0 +1,18 @@
1
+ FactoryBot.define do
2
+ factory :takeoff_calculator, class: Ecom::Core::TakeoffCalculator do
3
+ name { Ecom::Core::TakeoffCalculator::TAKEOFF_CALCULATOR_NAMES.sample }
4
+ is_custom_calculator { false }
5
+ input_parameters do
6
+ [
7
+ {
8
+ name: 'number_of_bar',
9
+ label: 'Number Of Bar',
10
+ input_type: 'number',
11
+ default_value: {
12
+ value: '1'
13
+ }
14
+ }
15
+ ]
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,6 @@
1
+ FactoryBot.define do
2
+ factory :takeoff, class: Ecom::Core::Takeoff do
3
+ association :task
4
+ takeoff_quantity { 33 }
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ FactoryBot.define do
2
+ factory :task_step_dependency, class: Ecom::Core::TaskStepDependency do
3
+ association :dependent_task_step, factory: :task_step
4
+ association :dependee_task_step, factory: :task_step
5
+ end
6
+ end
@@ -0,0 +1,8 @@
1
+ FactoryBot.define do
2
+ factory :task_step, class: Ecom::Core::TaskStep do
3
+ association :task
4
+ name { 'Cutting' }
5
+ total_contribution_percentage_to_task { 30 }
6
+ completed { false }
7
+ end
8
+ end
@@ -8,5 +8,11 @@ FactoryBot.define do
8
8
  association :task_template_type
9
9
  has_takeoff_fields { false }
10
10
  fields { [{ name: 'length', label: 'Length' }] }
11
+ task_steps do
12
+ [{
13
+ "name": 'Cutting',
14
+ "total_contribution_percentage_to_task": 100
15
+ }]
16
+ end
11
17
  end
12
18
  end
@@ -0,0 +1,10 @@
1
+ FactoryBot.define do
2
+ factory :work_order, class: Ecom::Core::WorkOrder do
3
+ name { FFaker::Name.unique.name }
4
+ association :assigned_to, factory: :crew
5
+ association :generated_by, factory: :user
6
+ start_date { (Time.now + 1.day).to_s }
7
+ end_date { (Time.now + 1.month).to_s }
8
+ status { Ecom::Core::WorkOrder::STATUSES.sample }
9
+ end
10
+ end
@@ -3,7 +3,6 @@ FactoryBot.define do
3
3
  name { FFaker::Name.name }
4
4
  description { FFaker::Name.name }
5
5
  design_reference_no { FFaker::Guid.guid }
6
- dimension { [{ label: 'Length', name: 'length', value: 12 }] }
7
6
  association :product_group
8
7
  association :work_product_template
9
8
  association :project
@@ -0,0 +1,10 @@
1
+ FactoryBot.define do
2
+ factory :measurement_unit, class: Ecom::Core::MeasurementUnit do
3
+ name { 'Meter' }
4
+ abbrivation { 'm' }
5
+ physical_quantity { Ecom::Core::MeasurementUnit::LENGTH }
6
+ is_si_unit { true }
7
+ conversion_factor { 1 }
8
+ system_of_measurement { Ecom::Core::MeasurementUnit::METRIC }
9
+ end
10
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ecom_core
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.28
4
+ version: 1.2.33
5
5
  platform: ruby
6
6
  authors:
7
7
  - Henock L.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-09-19 00:00:00.000000000 Z
11
+ date: 2020-10-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aasm
@@ -142,6 +142,20 @@ dependencies:
142
142
  - - "~>"
143
143
  - !ruby/object:Gem::Version
144
144
  version: 6.0.3
145
+ - !ruby/object:Gem::Dependency
146
+ name: json-schema
147
+ requirement: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - ">="
150
+ - !ruby/object:Gem::Version
151
+ version: '0'
152
+ type: :runtime
153
+ prerelease: false
154
+ version_requirements: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - ">="
157
+ - !ruby/object:Gem::Version
158
+ version: '0'
145
159
  - !ruby/object:Gem::Dependency
146
160
  name: factory_bot_rails
147
161
  requirement: !ruby/object:Gem::Requirement
@@ -238,6 +252,7 @@ files:
238
252
  - README.md
239
253
  - Rakefile
240
254
  - app/constants/ecom/core/status_constants.rb
255
+ - app/controllers/concerns/ecom/core/filterable.rb
241
256
  - app/controllers/concerns/ecom/core/lookupable.rb
242
257
  - app/controllers/concerns/ecom/core/resource_typeable.rb
243
258
  - app/controllers/ecom/core/access_controller.rb
@@ -269,6 +284,7 @@ files:
269
284
  - app/models/ecom/core/crew_type.rb
270
285
  - app/models/ecom/core/currency.rb
271
286
  - app/models/ecom/core/custom_payment_detail.rb
287
+ - app/models/ecom/core/dimension_element.rb
272
288
  - app/models/ecom/core/equipment.rb
273
289
  - app/models/ecom/core/equipment_category.rb
274
290
  - app/models/ecom/core/equipment_component.rb
@@ -286,6 +302,7 @@ files:
286
302
  - app/models/ecom/core/maintenance_status.rb
287
303
  - app/models/ecom/core/maintenance_type.rb
288
304
  - app/models/ecom/core/material_type.rb
305
+ - app/models/ecom/core/measurement_unit.rb
289
306
  - app/models/ecom/core/menu.rb
290
307
  - app/models/ecom/core/overtime_sheet.rb
291
308
  - app/models/ecom/core/overtime_sheet_entry.rb
@@ -293,6 +310,7 @@ files:
293
310
  - app/models/ecom/core/payment.rb
294
311
  - app/models/ecom/core/payment_detail.rb
295
312
  - app/models/ecom/core/payroll.rb
313
+ - app/models/ecom/core/plan.rb
296
314
  - app/models/ecom/core/product_group.rb
297
315
  - app/models/ecom/core/product_type.rb
298
316
  - app/models/ecom/core/project.rb
@@ -303,12 +321,17 @@ files:
303
321
  - app/models/ecom/core/schedule_unit.rb
304
322
  - app/models/ecom/core/stakeholder.rb
305
323
  - app/models/ecom/core/stakeholder_type.rb
324
+ - app/models/ecom/core/takeoff.rb
325
+ - app/models/ecom/core/takeoff_calculator.rb
306
326
  - app/models/ecom/core/task.rb
307
327
  - app/models/ecom/core/task_resource.rb
328
+ - app/models/ecom/core/task_step.rb
329
+ - app/models/ecom/core/task_step_dependency.rb
308
330
  - app/models/ecom/core/task_template.rb
309
331
  - app/models/ecom/core/task_template_type.rb
310
332
  - app/models/ecom/core/user.rb
311
333
  - app/models/ecom/core/user_role.rb
334
+ - app/models/ecom/core/work_order.rb
312
335
  - app/models/ecom/core/work_package.rb
313
336
  - app/models/ecom/core/work_product.rb
314
337
  - app/models/ecom/core/work_product_template.rb
@@ -328,6 +351,7 @@ files:
328
351
  - db/migrate/20190101112620_create_ecom_core_lookups.rb
329
352
  - db/migrate/20190101112625_create_ecom_core_overtime_types.rb
330
353
  - db/migrate/20191119010518_create_ecom_core_task_template_types.rb
354
+ - db/migrate/20191119012027_create_ecom_core_takeoff_calculators.rb
331
355
  - db/migrate/20191119012030_create_ecom_core_task_templates.rb
332
356
  - db/migrate/20191119013236_create_ecom_core_work_product_templates.rb
333
357
  - db/migrate/20191119144141_create_ecom_core_stakeholder_types.rb
@@ -344,9 +368,11 @@ files:
344
368
  - db/migrate/20191202221423_create_ecom_core_menus.rb
345
369
  - db/migrate/20191202222210_create_ecom_core_work_packages.rb
346
370
  - db/migrate/20191202235434_create_ecom_core_work_products.rb
371
+ - db/migrate/20191207103729_create_ecom_core_crews.rb
372
+ - db/migrate/20191207103730_create_ecom_core_plans.rb
373
+ - db/migrate/20191207103731_create_ecom_core_work_orders.rb
347
374
  - db/migrate/20191207103735_create_ecom_core_tasks.rb
348
375
  - db/migrate/20191210724614_create_ecom_core_task_resources.rb
349
- - db/migrate/20191225100054_create_ecom_core_crews.rb
350
376
  - db/migrate/20191225121850_create_ecom_core_project_crews.rb
351
377
  - db/migrate/20191225140433_create_ecom_core_attendance_sheets.rb
352
378
  - db/migrate/20191225162539_create_ecom_core_attendance_sheet_entries.rb
@@ -368,7 +394,12 @@ files:
368
394
  - db/migrate/20200602130247_create_ecom_core_requested_items.rb
369
395
  - db/migrate/20200602830603_create_ecom_core_bookings.rb
370
396
  - db/migrate/20200603115317_create_ecom_core_booked_items.rb
397
+ - db/migrate/20200813165553_create_ecom_core_measurement_units.rb
398
+ - db/migrate/20200814043632_create_ecom_core_takeoffs.rb
399
+ - db/migrate/20200820123719_create_ecom_core_task_steps.rb
400
+ - db/migrate/20200821130934_create_ecom_core_task_step_dependencies.rb
371
401
  - db/migrate/20200901085227_create_ecom_core_crew_contracts.rb
402
+ - db/migrate/20200901134912_create_ecom_core_dimension_elements.rb
372
403
  - db/migrate/20200919053331_create_ecom_core_maintenance_types.rb
373
404
  - db/migrate/20200919072216_create_ecom_core_schedule_settings.rb
374
405
  - db/migrate/20200919081338_create_ecom_core_maintenance_service_orders.rb
@@ -380,6 +411,7 @@ files:
380
411
  - lib/ecom/core/version.rb
381
412
  - lib/ecom_core.rb
382
413
  - lib/tasks/ecom_core_tasks.rake
414
+ - spec/factories/dimension_elements.rb
383
415
  - spec/factories/ecom/core/application_modules.rb
384
416
  - spec/factories/ecom/core/attendance_sheet_entries.rb
385
417
  - spec/factories/ecom/core/attendance_sheets.rb
@@ -420,6 +452,7 @@ files:
420
452
  - spec/factories/ecom/core/payment_details.rb
421
453
  - spec/factories/ecom/core/payments.rb
422
454
  - spec/factories/ecom/core/payrolls.rb
455
+ - spec/factories/ecom/core/plans.rb
423
456
  - spec/factories/ecom/core/product_groups.rb
424
457
  - spec/factories/ecom/core/product_types.rb
425
458
  - spec/factories/ecom/core/project_crews.rb
@@ -430,15 +463,21 @@ files:
430
463
  - spec/factories/ecom/core/schedule_units.rb
431
464
  - spec/factories/ecom/core/stakeholder_types.rb
432
465
  - spec/factories/ecom/core/stakeholders.rb
466
+ - spec/factories/ecom/core/takeoff_calculators.rb
467
+ - spec/factories/ecom/core/takeoffs.rb
433
468
  - spec/factories/ecom/core/task_resources.rb
469
+ - spec/factories/ecom/core/task_step_dependencies.rb
470
+ - spec/factories/ecom/core/task_steps.rb
434
471
  - spec/factories/ecom/core/task_template_types.rb
435
472
  - spec/factories/ecom/core/task_templates.rb
436
473
  - spec/factories/ecom/core/tasks.rb
437
474
  - spec/factories/ecom/core/user_roles.rb
438
475
  - spec/factories/ecom/core/users.rb
476
+ - spec/factories/ecom/core/work_orders.rb
439
477
  - spec/factories/ecom/core/work_packages.rb
440
478
  - spec/factories/ecom/core/work_product_templates.rb
441
479
  - spec/factories/ecom/core/work_products.rb
480
+ - spec/factories/measurement_units.rb
442
481
  homepage: http://www.mks.com.et
443
482
  licenses:
444
483
  - MIT