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

Could you have a look at the total_charge method?

I have an issue with the JobItems::Refund item.

The issue is that this will accept both hour for quantity or %, depending on the case. At the moment the JobItems::Refund item is not in the PERCENTAGE_TYPES or HOUR_TYPES since it could be in both.

Because of this I have the following situation:
GB -> 100 (qty - 9.5 h)
LBP -> 25 (qty - 25%)

(On cancelling unfilled job)

Refund -> 100 (qty - 9.5) - correct
Refund -> charge_rate(10.52) * qty(25) -> 250+ - wrong

The last refund item should use the % way of calculating its total_charge value. Any ideas?

@zainfur
Copy link

zainfur commented Nov 16, 2018

def total_charge
    if quantity.present?
      if PERCENTAGE_TYPES.include?(type)
percentage =  (quantity / 100.0).round(2)
        (charge_rate * self.job.number_of_hours * percentage).round(2)
      else if  HOURS_TYPES.include?(type) //Put this in - to future proof incase in future we have more - maybe a switch stamens will be better.
        (charge_rate * quantity).round(2)
      end
    end
  end

JobItem should have Qty, total, vat etc.

Because of this I have the following situation:
GB -> 100 (qty - 9.5 h)
LBP -> 25 (qty - 25%)

(On cancelling unfilled job)

Refund -> 100 (qty - 9.5) - correct
Refund -> charge_rate(10.52) * qty(25) -> 250+ - wrong //Z: Can't we look at type and determine if % or not?

For last bit

refund = totalOfJobItem x -1. - will give you negative of refund.

@martink-io
Copy link
Author

The issue is the the JobItem has Qty and total, but doesn't have a type. this is why I want to add the new column of type and then it would be easy. The whole issue just comes from the fact that Refund could be both of % and h type. New column will solve this instantly :)

@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