ecom_core 1.2.34 → 1.3.2

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 (133) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/ecom/core/{project_crews_controller.rb → site_crews_controller.rb} +5 -4
  3. data/app/controllers/ecom/core/unit_costs_controller.rb +29 -0
  4. data/app/models/ecom/core/attendance_sheet.rb +19 -19
  5. data/app/models/ecom/core/available_unit_of_measurement.rb +10 -0
  6. data/app/models/ecom/core/crew.rb +4 -2
  7. data/app/models/ecom/core/crew_contract.rb +41 -1
  8. data/app/models/ecom/core/crew_contract_transaction.rb +29 -0
  9. data/app/models/ecom/core/crew_id_card.rb +36 -0
  10. data/app/models/ecom/core/inspection_checklist.rb +6 -0
  11. data/app/models/ecom/core/lookahead_plan.rb +41 -0
  12. data/app/models/ecom/core/lookahead_plan_history.rb +16 -0
  13. data/app/models/ecom/core/lookahead_plan_review_time.rb +29 -0
  14. data/app/models/ecom/core/lookahead_plan_task_progress.rb +22 -0
  15. data/app/models/ecom/core/material.rb +6 -0
  16. data/app/models/ecom/core/material_identity.rb +21 -0
  17. data/app/models/ecom/core/material_item.rb +18 -0
  18. data/app/models/ecom/core/material_sub_type.rb +20 -0
  19. data/app/models/ecom/core/measurement_unit.rb +4 -14
  20. data/app/models/ecom/core/overtime_sheet.rb +13 -15
  21. data/app/models/ecom/core/payroll.rb +3 -3
  22. data/app/models/ecom/core/project.rb +0 -3
  23. data/app/models/ecom/core/project_template.rb +13 -0
  24. data/app/models/ecom/core/project_work_item_template.rb +9 -0
  25. data/app/models/ecom/core/resource_requisition.rb +21 -0
  26. data/app/models/ecom/core/resource_requisition_item.rb +45 -0
  27. data/app/models/ecom/core/{project_crew.rb → site.rb} +8 -4
  28. data/app/models/ecom/core/site_crew.rb +27 -0
  29. data/app/models/ecom/core/stakeholder.rb +1 -1
  30. data/app/models/ecom/core/task.rb +22 -9
  31. data/app/models/ecom/core/task_attachment.rb +11 -0
  32. data/app/models/ecom/core/task_inspection_checklist.rb +18 -0
  33. data/app/models/ecom/core/task_template.rb +20 -90
  34. data/app/models/ecom/core/task_template_inspection_checklist.rb +8 -0
  35. data/app/models/ecom/core/unit_cost.rb +27 -0
  36. data/app/models/ecom/core/unit_of_measure.rb +8 -0
  37. data/app/models/ecom/core/work_item_resource_requirement_template.rb +18 -0
  38. data/app/models/ecom/core/work_package.rb +3 -0
  39. data/app/models/ecom/core/work_product.rb +2 -18
  40. data/app/models/ecom/core/work_product_template.rb +2 -2
  41. data/app/serializers/ecom/core/unit_cost_serializer.rb +21 -0
  42. data/app/services/ecom/core/crew_contract_transaction_service.rb +89 -0
  43. data/app/services/ecom/core/menu_service.rb +2 -2
  44. data/app/services/ecom/core/site_crew_service.rb +44 -0
  45. data/app/uploaders/ecom/core/photo_uploader.rb +5 -1
  46. data/app/uploaders/ecom/core/task_attachment_uploader.rb +11 -0
  47. data/config/initializers/carrierwave.rb +8 -0
  48. data/config/routes.rb +4 -2
  49. data/db/migrate/20191118052213_create_ecom_core_unit_of_measures.rb +11 -0
  50. data/db/migrate/20191119012030_create_ecom_core_task_templates.rb +10 -8
  51. data/db/migrate/20191119013236_create_ecom_core_work_product_templates.rb +0 -15
  52. data/db/migrate/20191119021405_create_ecom_core_project_templates.rb +15 -0
  53. data/db/migrate/20191119034319_create_ecom_core_project_work_item_templates.rb +20 -0
  54. data/db/migrate/20191201145849_create_ecom_core_sites.rb +16 -0
  55. data/db/migrate/20191202222210_create_ecom_core_work_packages.rb +12 -0
  56. data/db/migrate/20191202235434_create_ecom_core_work_products.rb +2 -17
  57. data/db/migrate/20191207103730_create_ecom_core_lookahead_plans.rb +19 -0
  58. data/db/migrate/20191207103735_create_ecom_core_tasks.rb +15 -10
  59. data/db/migrate/20191225140433_create_ecom_core_attendance_sheets.rb +4 -4
  60. data/db/migrate/20200126081005_create_ecom_core_payrolls.rb +3 -3
  61. data/db/migrate/20200410090701_create_ecom_core_overtime_sheets.rb +4 -4
  62. data/db/migrate/20200616044231_create_ecom_core_material_sub_types.rb +14 -0
  63. data/db/migrate/20200616051902_create_ecom_core_material_identities.rb +17 -0
  64. data/db/migrate/20200618105233_create_ecom_core_material_items.rb +16 -0
  65. data/db/migrate/20200813165555_create_ecom_core_available_unit_of_measurements.rb +16 -0
  66. data/db/migrate/20200901085227_create_ecom_core_crew_contracts.rb +7 -1
  67. data/db/migrate/20201013072924_create_ecom_core_crew_contract_transactions.rb +16 -0
  68. data/db/migrate/20201013090609_create_ecom_core_site_crews.rb.rb +22 -0
  69. data/db/migrate/20201013094100_create_ecom_core_crew_id_cards.rb +16 -0
  70. data/db/migrate/20201113050953_create_ecom_core_task_inspection_checklists.rb +22 -0
  71. data/db/migrate/20201113094302_create_ecom_core_task_template_inspection_checklists.rb +17 -0
  72. data/db/migrate/20201121064916_create_ecom_core_unit_costs.rb +30 -0
  73. data/db/migrate/20201122123227_create_ecom_core_lookahead_plan_backlogs.rb +18 -0
  74. data/db/migrate/20201122170645_create_ecom_core_lookahead_plan_histories.rb +21 -0
  75. data/db/migrate/20201122170724_create_ecom_core_lookahead_plan_task_progresses.rb +21 -0
  76. data/db/migrate/20201123134917_create_ecom_core_task_attachments.rb +15 -0
  77. data/db/migrate/20201124171642_create_ecom_core_lookahead_plan_review_times.rb +17 -0
  78. data/db/migrate/20201125191158_create_ecom_core_work_item_resource_requirement_templates.rb +31 -0
  79. data/db/migrate/20201126191334_create_ecom_core_resource_requisitions.rb +23 -0
  80. data/db/migrate/20201126191349_create_ecom_core_resource_requisition_items.rb +33 -0
  81. data/lib/ecom/core/version.rb +1 -1
  82. data/spec/factories/ecom/core/attendance_sheets.rb +1 -1
  83. data/spec/factories/ecom/core/available_unit_of_measurements.rb +6 -0
  84. data/spec/factories/ecom/core/crew_contract_transactions.rb +8 -0
  85. data/spec/factories/ecom/core/crew_contracts.rb +12 -0
  86. data/spec/factories/ecom/core/crew_id_cards.rb +8 -0
  87. data/spec/factories/{dimension_elements.rb → ecom/core/dimension_elements.rb} +0 -0
  88. data/spec/factories/ecom/core/inspection_checklists.rb +5 -0
  89. data/spec/factories/ecom/core/lookahead_plan_histories.rb +9 -0
  90. data/spec/factories/ecom/core/lookahead_plan_review_times.rb +8 -0
  91. data/spec/factories/ecom/core/lookahead_plan_task_progresses.rb +9 -0
  92. data/spec/factories/ecom/core/lookahead_plans.rb +10 -0
  93. data/spec/factories/ecom/core/material_identities.rb +6 -0
  94. data/spec/factories/ecom/core/material_items.rb +6 -0
  95. data/spec/factories/ecom/core/material_sub_types.rb +6 -0
  96. data/spec/factories/ecom/core/materials.rb +5 -0
  97. data/spec/factories/{measurement_units.rb → ecom/core/measurement_units.rb} +6 -0
  98. data/spec/factories/ecom/core/overtime_sheets.rb +1 -1
  99. data/spec/factories/ecom/core/payrolls.rb +1 -1
  100. data/spec/factories/ecom/core/project_templates.rb +8 -0
  101. data/spec/factories/ecom/core/project_work_item_templates.rb +7 -0
  102. data/spec/factories/ecom/core/resource_requisition_items.rb +12 -0
  103. data/spec/factories/ecom/core/resource_requisitions.rb +9 -0
  104. data/spec/factories/ecom/core/site_crews.rb +10 -0
  105. data/spec/factories/ecom/core/sites.rb +8 -0
  106. data/spec/factories/ecom/core/task_attachments.rb +8 -0
  107. data/spec/factories/ecom/core/task_inspection_checklists.rb +11 -0
  108. data/spec/factories/ecom/core/task_template_inspection_checklists.rb +7 -0
  109. data/spec/factories/ecom/core/task_templates.rb +11 -6
  110. data/spec/factories/ecom/core/tasks.rb +9 -3
  111. data/spec/factories/ecom/core/unit_costs.rb +13 -0
  112. data/spec/factories/ecom/core/unit_of_measures.rb +7 -0
  113. data/spec/factories/ecom/core/work_item_resource_requirement_templates.rb +10 -0
  114. data/spec/factories/ecom/core/work_packages.rb +6 -0
  115. data/spec/factories/ecom/core/work_product_templates.rb +0 -1
  116. data/spec/factories/ecom/core/work_products.rb +1 -7
  117. metadata +97 -23
  118. data/app/controllers/concerns/ecom/core/filterable.rb +0 -14
  119. data/app/models/ecom/core/plan.rb +0 -18
  120. data/app/models/ecom/core/takeoff_calculator.rb +0 -115
  121. data/app/models/ecom/core/task_step.rb +0 -85
  122. data/app/models/ecom/core/task_step_dependency.rb +0 -10
  123. data/app/services/ecom/core/project_crew_service.rb +0 -39
  124. data/db/migrate/20191119012027_create_ecom_core_takeoff_calculators.rb +0 -11
  125. data/db/migrate/20191207103730_create_ecom_core_plans.rb +0 -12
  126. data/db/migrate/20191225121850_create_ecom_core_project_crews.rb +0 -19
  127. data/db/migrate/20200820123719_create_ecom_core_task_steps.rb +0 -17
  128. data/db/migrate/20200821130934_create_ecom_core_task_step_dependencies.rb +0 -16
  129. data/spec/factories/ecom/core/plans.rb +0 -8
  130. data/spec/factories/ecom/core/project_crews.rb +0 -9
  131. data/spec/factories/ecom/core/takeoff_calculators.rb +0 -18
  132. data/spec/factories/ecom/core/task_step_dependencies.rb +0 -6
  133. data/spec/factories/ecom/core/task_steps.rb +0 -8
@@ -0,0 +1,18 @@
1
+ module Ecom
2
+ module Core
3
+ class MaterialItem < ApplicationRecord
4
+ before_save :assign_serial_number
5
+
6
+ belongs_to :material_identity
7
+
8
+ validates :serial_number, presence: true, uniqueness: true
9
+ validates :material_identity_id, :material_identity, presence: true
10
+ validates :serial_number, format: { with: /^SN_\d+$/, message: 'Invalid serial number format', multiline: true }
11
+ validates :price, numericality: { greater_than: 0 }, allow_nil: true
12
+
13
+ def assign_serial_number
14
+ self.serial_number = "SN_#{(Time.now.to_f * 1000).to_i}"
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,20 @@
1
+ module Ecom
2
+ module Core
3
+ class MaterialSubType < ApplicationRecord
4
+ after_save :create_material_identity
5
+
6
+ belongs_to :material_type
7
+ has_many :material_identity
8
+
9
+ validates :name, presence: true, uniqueness: { case_sensitive: false, scope: :material_type_id }
10
+ validates :material_type_id, :material_type, presence: true
11
+
12
+ def create_material_identity
13
+ Ecom::Core::MaterialIdentity.create(
14
+ material_type_id: material_type_id,
15
+ material_sub_type_id: id
16
+ )
17
+ end
18
+ end
19
+ end
20
+ end
@@ -28,7 +28,10 @@ module Ecom
28
28
  validates :physical_quantity, inclusion: PHYSICAL_QUANTITIES
29
29
 
30
30
  validate :si_unit_with_conversion_factor
31
- validate :si_unit_system_of_measurement_and_physical_quantity
31
+ validates_uniqueness_of :is_si_unit, scope: %i[physical_quantity system_of_measurement],
32
+ if: -> { is_si_unit == true },
33
+ message: 'There exist an si unit of measurement for the '\
34
+ 'given physical quantity and system of measurement'
32
35
 
33
36
  def si_unit_with_conversion_factor
34
37
  if is_si_unit && conversion_factor != 1
@@ -37,19 +40,6 @@ module Ecom
37
40
  errors.add(:base, 'Only SI units can have a conversion factor 1')
38
41
  end
39
42
  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
43
  end
54
44
  end
55
45
  end
@@ -1,39 +1,37 @@
1
1
  module Ecom
2
2
  module Core
3
3
  class OvertimeSheet < ApplicationRecord
4
- validates :date, :opened_at, presence: true, uniqueness: { scope: :project_id }
4
+ validates :date, :opened_at, presence: true, uniqueness: { scope: :site_id }
5
5
  validates :status, inclusion: StatusConstants::STATUSES
6
6
 
7
- belongs_to :project
7
+ belongs_to :site
8
8
 
9
9
  has_many :overtime_sheet_entries
10
10
  has_many :crew_overtimes, through: :overtime_sheet_entries
11
11
 
12
- scope :by_project, ->(id) { where(project_id: id) }
12
+ scope :by_site, ->(id) { where(site_id: id) }
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) }
18
16
 
19
- def self.open_exists?(project_id)
17
+ def self.open_exists?(site_id)
20
18
  OvertimeSheet
21
- .by_project(project_id)
19
+ .by_site(site_id)
22
20
  .by_status(StatusConstants::OPEN)
23
21
  .exists?
24
22
  end
25
23
 
26
- def self.open_for_date_exists?(date, project_id)
24
+ def self.open_for_date_exists?(date, site_id)
27
25
  OvertimeSheet
28
- .by_project(project_id)
26
+ .by_site(site_id)
29
27
  .by_status(StatusConstants::OPEN)
30
28
  .by_date(date)
31
29
  .exists?
32
30
  end
33
31
 
34
- def self.exists_for_date?(date, project_id)
32
+ def self.exists_for_date?(date, site_id)
35
33
  OvertimeSheet
36
- .by_project(project_id)
34
+ .by_site(site_id)
37
35
  .by_date(date)
38
36
  .exists?
39
37
  end
@@ -43,18 +41,18 @@ module Ecom
43
41
  # check if there is an open overtime already,
44
42
  # and also that we have only one open overtime
45
43
  # sheet at a time.
46
- def self.create_new(date, project_id)
47
- if OvertimeSheet.exists_for_date?(date, project_id)
44
+ def self.create_new(date, site_id)
45
+ if OvertimeSheet.exists_for_date?(date, site_id)
48
46
  raise 'There is already an overtime sheet for the selected date.'
49
47
  end
50
48
 
51
- if OvertimeSheet.open_exists?(project_id)
49
+ if OvertimeSheet.open_exists?(site_id)
52
50
  open_overtime_sheet = OvertimeSheet.find_by(status: 'Open')
53
51
  raise "There is already an open overtime sheet for #{open_overtime_sheet.date}.
54
52
  It has to be submitted before creating a new one."
55
53
  end
56
54
 
57
- OvertimeSheet.create(date: date, opened_at: Time.now, status: StatusConstants::OPEN, project_id: project_id)
55
+ OvertimeSheet.create(date: date, opened_at: Time.now, status: StatusConstants::OPEN, site_id: site_id)
58
56
  end
59
57
 
60
58
  def submit
@@ -4,9 +4,9 @@ module Ecom
4
4
  validates :month, :year, presence: true
5
5
 
6
6
  has_many :payments, class_name: 'Ecom::Core::Payment'
7
- belongs_to :project
7
+ belongs_to :site
8
8
 
9
- scope :by_project, ->(id) { where(project_id: id) }
9
+ scope :by_site, ->(id) { where(site_id: id) }
10
10
  scope :by_month, ->(month) { where(month: month) }
11
11
  scope :by_year, ->(year) { where(year: year) }
12
12
 
@@ -17,7 +17,7 @@ module Ecom
17
17
  m = 1
18
18
  y += 1
19
19
  end
20
- Payroll.create(month: m, year: y, project_id: project_id)
20
+ Payroll.create(month: m, year: y, site_id: site_id)
21
21
  end
22
22
  end
23
23
  end
@@ -9,9 +9,6 @@ module Ecom
9
9
  belongs_to :currency
10
10
  belongs_to :company
11
11
 
12
- has_many :project_crews
13
- has_many :crews, through: :project_crews
14
-
15
12
  validates :name, :location, :contract_number, :date_contract_signed, :commencement_date, :completion_date,
16
13
  :contract_amount, :advance_payment, :retention, presence: true
17
14
  end
@@ -0,0 +1,13 @@
1
+ module Ecom
2
+ module Core
3
+ class ProjectTemplate < ApplicationRecord
4
+ belongs_to :task_template_type
5
+ has_many :project_work_item_templates
6
+
7
+ validates :code, :name, presence: true
8
+ validates_uniqueness_of :code
9
+
10
+ delegate(:name, to: :task_template_type, prefix: true)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ module Ecom
2
+ module Core
3
+ class ProjectWorkItemTemplate < ApplicationRecord
4
+ belongs_to :task_template
5
+ belongs_to :work_product_template
6
+ belongs_to :project_template
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,21 @@
1
+ module Ecom
2
+ module Core
3
+ class ResourceRequisition < ApplicationRecord
4
+ DRAFT = 'Draft'.freeze
5
+ SUBMITTED = 'Submitted'.freeze
6
+ APPROVED = 'Approved'.freeze
7
+ REJECTED = 'Rejected'.freeze
8
+
9
+ STATUSES = [DRAFT, SUBMITTED, APPROVED, REJECTED].freeze
10
+
11
+ belongs_to :lookahead_plan
12
+ belongs_to :reviewed_by, class_name: 'Ecom::Core::User', optional: true
13
+ belongs_to :approved_by, class_name: 'Ecom::Core::User', optional: true
14
+ has_many :resource_requisition_items
15
+
16
+ validates :delivery_point, presence: true
17
+
18
+ validates :status, presence: true, inclusion: STATUSES
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,45 @@
1
+ module Ecom
2
+ module Core
3
+ class ResourceRequisitionItem < ApplicationRecord
4
+ PENDING = 'Pending'.freeze
5
+ APPROVED = 'Approved'.freeze
6
+ REJECTED = 'Rejected'.freeze
7
+
8
+ STATUSES = [PENDING, APPROVED, REJECTED].freeze
9
+
10
+ belongs_to :resource_requisition
11
+ belongs_to :resource_type
12
+ belongs_to :requested_quantity_measurement_unit, class_name: 'Ecom::Core::MeasurementUnit'
13
+ belongs_to :awaiting_quantity_measurement_unit, class_name: 'Ecom::Core::MeasurementUnit'
14
+
15
+ validates :due_date, presence: true
16
+
17
+ validates :requested_quantity, presence: true, numericality: { greater_than: 0 }
18
+ validates :awaiting_quantity, presence: true, numericality: { greater_than: 0 }
19
+
20
+ validates :status, presence: true, inclusion: STATUSES
21
+
22
+ validate :quantity_validator
23
+
24
+ def quantity_validator
25
+ if requested_quantity.nil? || awaiting_quantity.nil? ||
26
+ requested_quantity_measurement_unit_id.nil? ||
27
+ awaiting_quantity_measurement_unit_id.nil?
28
+ return
29
+ end
30
+
31
+ requested_quantity_measurement_unit =
32
+ Ecom::Core::MeasurementUnit.find_by(id: requested_quantity_measurement_unit_id)
33
+ awaiting_quantity_measurement_unit =
34
+ Ecom::Core::MeasurementUnit.find_by(id: awaiting_quantity_measurement_unit_id)
35
+
36
+ requested_quantity_in_si_unit = requested_quantity / requested_quantity_measurement_unit.conversion_factor
37
+ awaiting_quantity_in_si_unit = awaiting_quantity / awaiting_quantity_measurement_unit.conversion_factor
38
+
39
+ return unless awaiting_quantity_in_si_unit > requested_quantity_in_si_unit
40
+
41
+ errors.add(:awaiting_quantity, 'awaiting quantity can not be greater than requested quantity')
42
+ end
43
+ end
44
+ end
45
+ end
@@ -1,15 +1,19 @@
1
1
  module Ecom
2
2
  module Core
3
- class ProjectCrew < ApplicationRecord
3
+ class Site < ApplicationRecord
4
4
  ACTIVE = 'Active'.freeze
5
5
  INACTIVE = 'Inactive'.freeze
6
+
6
7
  STATUSES = [ACTIVE, INACTIVE].freeze
7
8
 
8
- belongs_to :project
9
- belongs_to :crew
9
+ validates :name, :project_id, :project, :address, :status, presence: true
10
10
 
11
- validates :start_date, :status, presence: true
12
11
  validates :status, inclusion: STATUSES
12
+
13
+ belongs_to :project
14
+
15
+ has_many :site_crews
16
+ has_many :crews, through: :site_crews
13
17
  end
14
18
  end
15
19
  end
@@ -0,0 +1,27 @@
1
+ module Ecom
2
+ module Core
3
+ class SiteCrew < ApplicationRecord
4
+ TEMPORARY_SITE_CREW = 'Temporary site crew'.freeze
5
+ PERMANENT_SITE_CREW = 'Permanent site crew'.freeze
6
+
7
+ SITE_CREW_TYPES = [TEMPORARY_SITE_CREW, PERMANENT_SITE_CREW].freeze
8
+
9
+ ACTIVE = 'Active'.freeze
10
+ INACTIVE = 'Inactive'.freeze
11
+ STATUSES = [ACTIVE, INACTIVE].freeze
12
+
13
+ validates :crew_id, :crew, :site_id, :site, :start_date, :site_crew_type, :status, presence: true
14
+
15
+ validates_uniqueness_of :site_id,
16
+ scope: :crew_id,
17
+ if: -> { status == 'Active' },
18
+ message: 'There can only be one record with status `Active` for a given site and crew'
19
+
20
+ validates :site_crew_type, inclusion: SITE_CREW_TYPES
21
+ validates :status, inclusion: STATUSES
22
+
23
+ belongs_to :crew
24
+ belongs_to :site
25
+ end
26
+ end
27
+ end
@@ -5,7 +5,7 @@ module Ecom
5
5
 
6
6
  validates :name, presence: true, uniqueness: true
7
7
 
8
- delegate :name, to: :stakeholder_type, prefix: true
8
+ delegate(:name, to: :stakeholder_type, prefix: true)
9
9
  end
10
10
  end
11
11
  end
@@ -5,34 +5,47 @@ module Ecom
5
5
 
6
6
  has_ancestry
7
7
 
8
+ NOT_INSPECTED = 'Not Inspected'.freeze
9
+ IN_PROGRESS = 'In Progress'.freeze
10
+ PASS = 'Pass'.freeze
11
+ FAIL = 'Fail'.freeze
12
+
13
+ INSPECTION_STATUSES = [NOT_INSPECTED, IN_PROGRESS, PASS, FAIL].freeze
14
+
8
15
  belongs_to :work_product
9
16
  belongs_to :task_template
10
17
  belongs_to :work_package, optional: true
11
18
  belongs_to :work_order, optional: true
12
- belongs_to :plan, optional: true
13
19
  belongs_to :performer, class_name: 'Ecom::Core::User', optional: true
14
- belongs_to :approver, class_name: 'Ecom::Core::User', optional: true
15
- belongs_to :supervisor, class_name: 'Ecom::Core::User', optional: true
16
- belongs_to :quality_controller, class_name: 'Ecom::Core::User', optional: true
20
+ belongs_to :client_consultant, class_name: 'Ecom::Core::User', optional: true
21
+ belongs_to :foreman, class_name: 'Ecom::Core::User', optional: true
22
+ belongs_to :inspector, class_name: 'Ecom::Core::User', optional: true
23
+ belongs_to :change_order_for, class_name: 'Ecom::Core::User', optional: true
17
24
 
18
- has_many :task_steps
19
25
  has_many :task_resources
20
26
  has_one :takeoff
27
+ has_one :change_order, foreign_key: :change_order_for_id, class_name: 'Ecom::Core::Task'
21
28
 
22
29
  validates_with DateRangeValidator
23
- validates :code, :name, :status, :percent_completed, presence: true
30
+ validates :code, :name, :status, :inspection_status, :percent_completed, presence: true
24
31
  validates_numericality_of :percent_completed,
25
32
  only_integer: true,
26
33
  greater_than_or_equal_to: 0,
27
34
  less_than_or_equal_to: 100
35
+ validates :percentage_contribution,
36
+ numericality: {
37
+ greater_than_or_equal_to: 0,
38
+ less_than_or_equal_to: 100,
39
+ only_integer: true
40
+ },
41
+ allow_nil: true
42
+
43
+ validates_inclusion_of :inspection_status, in: INSPECTION_STATUSES
28
44
 
29
45
  scope :by_status, ->(status) { where(status: status) }
30
46
 
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
33
47
  aasm column: 'status' do
34
48
  state :new, initial: true
35
- state :planned
36
49
  state :ready_to_start
37
50
  state :in_progress
38
51
  state :submitted
@@ -0,0 +1,11 @@
1
+ module Ecom
2
+ module Core
3
+ class TaskAttachment < ApplicationRecord
4
+ mount_base64_uploader :file, TaskAttachmentUploader
5
+
6
+ belongs_to :task
7
+
8
+ validates :title, presence: true
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,18 @@
1
+ module Ecom
2
+ module Core
3
+ class TaskInspectionChecklist < ApplicationRecord
4
+ NOT_INSPECTED = 'Not Inspected'.freeze
5
+ IN_PROGRESS = 'In Progress'.freeze
6
+ PASS = 'Pass'.freeze
7
+ FAIL = 'Fail'.freeze
8
+
9
+ INSPECTION_STATUSES = [NOT_INSPECTED, IN_PROGRESS, PASS, FAIL].freeze
10
+
11
+ belongs_to :inspected_by, class_name: 'Ecom::Core::User'
12
+ belongs_to :task
13
+
14
+ validates :name, :status, presence: true
15
+ validates :status, inclusion: INSPECTION_STATUSES
16
+ end
17
+ end
18
+ end
@@ -1,57 +1,30 @@
1
- require 'json-schema'
2
1
  module Ecom
3
2
  module Core
4
3
  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
-
40
4
  has_ancestry
41
5
 
42
6
  belongs_to :task_template_type
43
- has_and_belongs_to_many :work_product_templates, join_table: 'ecom_core_task_templates_work_product_templates'
7
+ belongs_to :unit_of_measure
8
+
9
+ has_many :task_template_inspection_checklists
10
+ has_many :inspection_checklists, through: :task_template_inspection_checklists
11
+ has_many :project_work_item_templates
12
+ has_many :work_product_templates, through: :project_work_item_templates
44
13
  has_and_belongs_to_many :resource_types, join_table: 'ecom_core_task_templates_resource_types'
45
- belongs_to :takeoff_calculator, optional: true
46
14
 
47
- validates :name, :code, presence: true
15
+ validates :name, :code, :takeoff_fields, :task_completion_detail, presence: true
48
16
  validates :code, uniqueness: true
17
+ validates :percentage_contribution,
18
+ numericality: {
19
+ greater_than_or_equal_to: 0,
20
+ less_than_or_equal_to: 100,
21
+ only_integer: true
22
+ },
23
+ allow_nil: true
24
+
49
25
  delegate(:name, to: :task_template_type, prefix: true)
50
26
 
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
27
+ validate :percentage_contribution_sum_validator
55
28
 
56
29
  def full_name
57
30
  parent_name = parent&.name
@@ -72,54 +45,11 @@ module Ecom
72
45
  resource_types.where(type: 'Ecom::Core::EquipmentType')
73
46
  end
74
47
 
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
48
+ def percentage_contribution_sum_validator
49
+ return if percentage_contribution.nil?
118
50
 
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
51
+ sum = siblings.sum(:percentage_contribution)
52
+ errors.add(:task, 'Sum of percentage contributions has to be 100') if sum > 100
123
53
  end
124
54
  end
125
55
  end