diff --git a/app/models/billing/package_counter.rb b/app/models/billing/package_counter.rb index d7d43b735..3deac304c 100644 --- a/app/models/billing/package_counter.rb +++ b/app/models/billing/package_counter.rb @@ -28,6 +28,10 @@ class Billing::PackageCounter < ApplicationRecord belongs_to :service, class_name: 'Billing::Service', optional: true validates :duration, presence: true + validates :duration, allow_nil: true, numericality: { only_integer: true } + validates :exclude, inclusion: { in: [true, false] } + + before_save { self.prefix ||= '' } def display_name "PC##{id}" diff --git a/app/models/billing/provisioning/base.rb b/app/models/billing/provisioning/base.rb index 6fb89f5a7..e6c8ab734 100644 --- a/app/models/billing/provisioning/base.rb +++ b/app/models/billing/provisioning/base.rb @@ -11,6 +11,10 @@ def initialize(service) @service = service end + def after_create + nil + end + # Called before renewing the service def before_renew nil diff --git a/app/models/billing/provisioning/free_minutes.rb b/app/models/billing/provisioning/free_minutes.rb new file mode 100644 index 000000000..9c6f63067 --- /dev/null +++ b/app/models/billing/provisioning/free_minutes.rb @@ -0,0 +1,96 @@ +# frozen_string_literal: true + +module Billing + module Provisioning + # Accepts Service Type variables in format: + # { + # "prefixes": [ + # { + # "prefix": "123", + # "duration": 60, + # "exclude": false + # }, + # ... + # ] + # } + # Accepts Service variables in format: + # { + # "prefixes": [ + # { + # "prefix": "456", + # "duration": 60, + # "exclude": false + # }, + # ... + # ], + # "ignore_prefixes": ["123", ...] + # } + # "exclude" is optional and defaults to false + # "ignore_prefixes" is optional and defaults to [] + # + class FreeMinutes < Base + def after_create + raise ArgumentError, 'No prefixes configured' if prefixes.empty? + + prefixes_data.each do |data| + create_or_reset_counter(data) + end + end + + def after_success_renew + raise ArgumentError, 'No prefixes configured' if prefixes.empty? + + prefixes_data.each do |data| + create_or_reset_counter(data) + end + destroy_obsolete_counters + end + + private + + # if counter for prefix does not exist - will created it. + # if counter for prefix exists - will reset duration and exclude. + def create_or_reset_counter(data) + counter = Billing::PackageCounter.find_or_initialize_by(account:, service:, prefix: data['prefix']) + counter.assign_attributes( + duration: data['duration'], + exclude: data['exclude'] + ) + counter.save! + end + + def destroy_obsolete_counters + Billing::PackageCounter.where(service:).where.not(prefix: prefixes).find_each(&:destroy!) + end + + def prefixes + prefixes_data.map { |data| data['prefix'] } + end + + def prefixes_data + @prefixes_data ||= build_prefixes_data + end + + def build_prefixes_data + # service may override some service.type prefixes + ignore_type_prefixes = service.variables['prefixes'].map { |data| data['prefix'] } + # service may ignore some service.type prefixes + ignore_type_prefixes += service.variables['ignore_prefixes'] || [] + + data_list = [] + service.type.variables['prefixes'].each do |data| + next if ignore_type_prefixes.include? data['prefix'] + + data_list << data + end + service.variables['prefixes'].each do |data| + data_list << data + end + data_list.map do |data| + data['exclude'] = false if data['exclude'].nil? + data + end + end + end + end +end diff --git a/app/models/billing/provisioning/logging.rb b/app/models/billing/provisioning/logging.rb index abe1344b8..69593fa83 100644 --- a/app/models/billing/provisioning/logging.rb +++ b/app/models/billing/provisioning/logging.rb @@ -3,6 +3,10 @@ module Billing module Provisioning class Logging < Base + def after_create + Rails.logger.info "Service created service_id=#{service.id}" + end + def before_renew Rails.logger.info "Renew started service_id=#{service.id}" end diff --git a/app/models/billing/service.rb b/app/models/billing/service.rb index 779abde55..7d20df606 100644 --- a/app/models/billing/service.rb +++ b/app/models/billing/service.rb @@ -53,6 +53,7 @@ class Billing::Service < ApplicationRecord belongs_to :type, class_name: 'Billing::ServiceType' belongs_to :account, class_name: 'Account' has_many :transactions, class_name: 'Billing::Transaction', dependent: :restrict_with_error + has_many :package_counters, class_name: 'Billing::PackageCounter', dependent: :destroy attr_readonly :account_id, :type_id @@ -63,6 +64,7 @@ class Billing::Service < ApplicationRecord validate :validate_variables after_create :create_initial_transaction + after_create :provisioning_object_after_create scope :ready_for_renew, lambda { where('renew_period_id is not null AND renew_at <= ? ', Time.current) @@ -98,8 +100,16 @@ def variables_json=(value) self.variables = value end + def build_provisioning_object + type.provisioning_class.constantize.new(self) + end + private + def provisioning_object_after_create + build_provisioning_object.after_create + end + def validate_variables errors.add(:variables, 'must be a JSON object or empty') if !variables.nil? && !variables.is_a?(Hash) end diff --git a/app/models/billing/service/renew.rb b/app/models/billing/service/renew.rb index 30a4a2f34..822460ece 100644 --- a/app/models/billing/service/renew.rb +++ b/app/models/billing/service/renew.rb @@ -45,7 +45,7 @@ def perform private def provisioning_object - @provisioning_object ||= service.type.provisioning_class.constantize.new(service) + @provisioning_object ||= service.build_provisioning_object end def next_renew_at