Skip to content

Instantly share code, notes, and snippets.

@martink-io
Created November 15, 2018 02:04
Show Gist options
  • Save martink-io/0eb97eacb868c65338365635d12b7da4 to your computer and use it in GitHub Desktop.
Save martink-io/0eb97eacb868c65338365635d12b7da4 to your computer and use it in GitHub Desktop.
class JobItem < ApplicationRecord
VAT_RATE = 0.2
AMENDMENT_FORM_LABELS = ['Lateness', 'Full Refund'].freeze
AMENDMENT_TYPES = ['JobItems::Lateness', 'JobItems::Refund'].freeze
CHARGABLE_TYPES = ['JobItems::GuardBooking', 'JobItems::LateBookingPenalty'].freeze
REFUNDABLE_TYPES = ['JobItems::Lateness', 'JobItems::Refund'].freeze
PERCENTAGE_TYPES = ['JobItems::CancelationPenalty', 'JobItems::LateBookingPenalty'].freeze
HOURS_TYPES = ['JobItems::GuardBooking', 'JobItems::Lateness',].freeze
belongs_to :job
belongs_to :resource, polymorphic: true
has_one :job_item_payment, dependent: :destroy
has_one :payment, through: :job_item_payment, dependent: :destroy
validate :quantity_is_present
validate :guard_job_exists
validate :max_hours
validate :max_refund_exceeded
before_save :set_vat
def total_pay
if quantity.present?
if PERCENTAGE_TYPES.include?(type)
(((pay_rate * self.job.number_of_hours) * quantity) / 100.0).round(2)
else
(pay_rate * quantity).round(2)
end
end
end
def total_charge
if quantity.present?
if PERCENTAGE_TYPES.include?(type)
(((charge_rate * self.job.number_of_hours) * quantity) / 100.0).round(2)
else
(charge_rate * quantity).round(2)
end
end
end
def total
(total_charge + vat).round(2)
end
def quantity_is_present
errors[:hours] << "Please select a duration" unless quantity.present?
end
def guard_job_exists
errors[:guard_id] << "Please select a guard" unless resource.present?
end
def max_hours
return unless quantity.present?
if HOURS_TYPES.include?(type)
errors[:hours] << "The amount of hours can not exceed job's length#{self.job.number_of_hours}" if quantity > self.job.number_of_hours
end
end
def max_refund_exceeded
return unless quantity.present?
amendments_amount = self.job.job_items.where(type: REFUNDABLE_TYPES).map(&:total).sum
if amendments_amount > self.job.total_charge
errors[:base] << "You've exceeded maximum refundable amount"
end
end
def vat
vat = (total_charge * VAT_RATE).round(2)
end
private
def set_vat
vat = (total_charge * VAT_RATE).round(2)
end
end
@martink-io
Copy link
Author

martink-io commented Nov 16, 2018

Yes, we can use switch statement to determine TYPES and use different formula based on it. However, with the new column, we wouldn't need the immutable arrays (enums in Java) and will only switch(self.type) case '%', case 'h' and whatever we have later on

@zainfur
Copy link

zainfur commented Nov 25, 2018

Why do you have to work add column for type - can you not work out from Type of JobItem what quantity will be?
i.e.
if JI is lateness - we know it is hrs.
If JI is Penalty we know it is %

In Java we can do something like this

Switch (TYPE){ //Type of JobItem

case Penalty, LBP, CancellationCharge: {
//% do percentage calculation
}
break;
case GuardBooking, Lateness: {
//This is always hours
}
break:

} //Close Switch

With this approach we don't need new column of % or hrs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment