Module: Plutonium::Models::HasCents::ClassMethods

Defined in:
lib/plutonium/models/has_cents.rb

Instance Method Summary collapse

Instance Method Details

#has_cents(cents_name, name: nil, rate: 100, suffix: "amount", unit: nil) ⇒ Object

super(*args, options, &block) end Defines getter and setter methods for a monetary value stored as cents, and ensures validations are applied to both cents and decimal attributes.

Examples:

Standard currency (dollars and cents)

has_cents :price_cents

Static currency symbol

has_cents :price_cents, unit: "£"

Per-row currency symbol read off the record

has_cents :price_cents, unit: :currency_symbol

Custom rate for a different currency division

has_cents :amount_cents, name: :cost, rate: 1000

Whole number storage without decimal places

has_cents :quantity_cents, name: :quantity, rate: 1

Using custom suffix

has_cents :total_cents, suffix: "value"

Parameters:

  • cents_name (Symbol)

    The name of the attribute storing the cents value.

  • name (Symbol, nil) (defaults to: nil)

    The name for the generated methods. If nil, it's derived from cents_name.

  • rate (Integer) (defaults to: 100)

    The conversion rate from the decimal value to cents (default: 100). This represents how many cents are in one unit of the decimal value. For example:

    • rate: 100 for dollars/cents (1 dollar = 100 cents)
    • rate: 1000 for dollars/mils (1 dollar = 1000 mils)
    • rate: 1 for a whole number representation
  • suffix (String) (defaults to: "amount")

    The suffix to append to the cents_name if name is not provided (default: "amount").

  • unit (String, Symbol, nil) (defaults to: nil)

    The currency unit used when the value is rendered as currency. A String is used verbatim as the symbol ("£"); a Symbol names a method read off the record for per-row currencies (unit: :currency_symbol); nil (default) renders with no symbol. Consumers (the Currency display component, grid/kanban cards) read this via Plutonium::Models::HasCents#has_cents_unit_for.



152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/plutonium/models/has_cents.rb', line 152

def has_cents(cents_name, name: nil, rate: 100, suffix: "amount", unit: nil)
  cents_name = cents_name.to_sym
  name ||= cents_name.to_s.gsub(/_cents$/, "")
  name = name.to_sym
  name = (name == cents_name) ? :"#{cents_name}_#{suffix}" : name

  self.has_cents_attributes = has_cents_attributes.merge(
    cents_name => {name: name, rate: rate, unit: unit}
  )

  class_eval <<-RUBY, __FILE__, __LINE__ + 1
    # Getter method for the decimal representation of the cents value.
    #
    # @return [BigDecimal, nil] The decimal value or nil if cents_name is not present.
    def #{name}
      #{cents_name}.to_d / #{rate} if #{cents_name}.present?
    end

    # Setter method for the decimal representation of the cents value.
    #
    # @param value [Numeric, nil] The decimal value to be set.
    def #{name}=(value)
      self.#{cents_name} = begin
        (BigDecimal(value.to_s) * #{rate}).to_i if value.present?
      rescue ArgumentError
        nil
      end
    end

    # Mark decimal field as invalid if cents field is not valid
    after_validation do
      next unless errors[#{cents_name.inspect}].present?

      errors.add(#{name.inspect}, :invalid)
    end
  RUBY
end

#has_cents_attribute?(attribute) ⇒ Boolean

Checks if a given attribute is defined with has_cents

Parameters:

  • attribute (Symbol)

    The attribute to check

Returns:

  • (Boolean)

    true if the attribute is defined with has_cents, false otherwise



194
195
196
# File 'lib/plutonium/models/has_cents.rb', line 194

def has_cents_attribute?(attribute)
  has_cents_attributes.key?(attribute.to_sym)
end

#has_cents_decimal_attribute?(attribute) ⇒ Boolean

Checks if a given attribute is the decimal accessor of a has_cents pair (e.g. :amount for has_cents :amount_cents).

Parameters:

  • attribute (Symbol)

    The attribute to check

Returns:

  • (Boolean)


203
204
205
206
# File 'lib/plutonium/models/has_cents.rb', line 203

def has_cents_decimal_attribute?(attribute)
  attribute = attribute.to_sym
  has_cents_attributes.any? { |_, opts| opts[:name] == attribute }
end