Module: SpreeCmCommissioner::OrderDecorator

Defined in:
app/models/spree_cm_commissioner/order_decorator.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.prepended(base) ⇒ Object

rubocop:disable Metrics/MethodLength



3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 3

def self.prepended(base) # rubocop:disable Metrics/MethodLength
  base.include SpreeCmCommissioner::StoreMetadata
  base.include SpreeCmCommissioner::PhoneNumberSanitizer
  base.include SpreeCmCommissioner::OrderIntegration
  base.include SpreeCmCommissioner::OrderSeatable
  base.include SpreeCmCommissioner::OrderStateMachine
  base.include SpreeCmCommissioner::RouteOrderCountable
  base.include SpreeCmCommissioner::OrderScopes

  base.before_create :link_by_phone_number
  base.before_create :associate_customer
  base.before_create :set_tenant_id
  base.after_commit :increment_route_order_count, on: :create

  base. :preload_trip_ids, :array, default: []

  base.validates :promo_total, base::MONEY_VALIDATION
  base.validate :validate_channel_prefix, if: :channel_changed?
  base.validates :phone_number, presence: true, if: :require_phone_number

  base.has_one :invoice, dependent: :destroy, class_name: 'SpreeCmCommissioner::Invoice'
  base.has_one :customer, class_name: 'SpreeCmCommissioner::Customer', through: :subscription

  base.belongs_to :tenant, class_name: 'SpreeCmCommissioner::Tenant', optional: true
  base.belongs_to :subscription, class_name: 'SpreeCmCommissioner::Subscription', optional: true

  base.has_many :taxons, class_name: 'Spree::Taxon', through: :customer
  base.has_many :vendors, through: :products, class_name: 'Spree::Vendor'
  base.has_many :taxons, through: :products, class_name: 'Spree::Taxon'
  base.has_many :guests, through: :line_items, class_name: 'SpreeCmCommissioner::Guest'

  base.has_many :saved_guests,
                through: :guests,
                source: :saved_guest,
                class_name: 'SpreeCmCommissioner::SavedGuest'

  base.has_many :blocks, through: :guests, class_name: 'SpreeCmCommissioner::Block', source: :block
  base.has_many :reserved_blocks, through: :guests, class_name: 'SpreeCmCommissioner::ReservedBlock'
  base.has_many :guest_card_classes, class_name: 'SpreeCmCommissioner::GuestCardClass', through: :variants
  base.has_many :product_completion_steps, class_name: 'SpreeCmCommissioner::ProductCompletionStep', through: :line_items

  base.delegate :customer, to: :user, allow_nil: true

  base.whitelisted_ransackable_associations |= %w[customer taxon payments guests invoice]
  base.whitelisted_ransackable_attributes |= %w[intel_phone_number phone_number email number state]

  base.accepts_nested_attributes_for :saved_guests, allow_destroy: true

  def base.search_by_qr_data!(data)
    token = data.match(/^R\d{9,}-([A-Za-z0-9_\-]+)$/)&.captures

    raise ActiveRecord::RecordNotFound, "Couldn't find Spree::Order with QR data: #{data}" unless token

    find_by!(token: token)
  end
end

Instance Method Details

#associate_user!(user, override_email = true) ⇒ Object

overrided add phone_number trigger when update customer detail



133
134
135
136
137
138
139
140
141
142
143
144
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 133

def associate_user!(user, override_email = true) # rubocop:disable Style/OptionalBooleanParameter
  self.user           = user
  self.email          = user.email if override_email
  self.phone_number   = user.phone_number if user.phone_number.present?
  self.created_by   ||= user
  self.bill_address ||= user.bill_address.try(:clone)
  self.ship_address ||= user.ship_address.try(:clone)

  changes = slice(:user_id, :email, :phone_number, :created_by_id, :bill_address_id, :ship_address_id)

  self.class.unscoped.where(id: self).update_all(changes) # rubocop:disable Rails/SkipsModelValidations
end

#collect_payment_methods(store = nil) ⇒ Object

override



106
107
108
109
110
111
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 106

def collect_payment_methods(store = nil)
  return super if user.blank?
  return super unless user.early_adopter?

  collect_payment_methods_for_early_adopter(store)
end

#collect_payment_methods_for_early_adopter(store = nil) ⇒ Object



113
114
115
116
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 113

def collect_payment_methods_for_early_adopter(store = nil)
  store ||= self.store
  store.payment_methods.available_on_frontend_for_early_adopter.select { |pm| pm.available_for_order?(self) }
end

#create_default_payment_if_eligbleObject

assume check is default payment method for subscription



167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 167

def create_default_payment_if_eligble
  return unless subscription?

  if covered_by_store_credit
    payment_method = Spree::PaymentMethod::StoreCredit.available_on_back_end.first_or_create! do |method|
      method.name ||= 'StoreCredit'
      method.stores = [Spree::Store.default] if method.stores.empty?
    end
    source_id = user.store_credit_ids.last
    source_type = 'Spree::StoreCredit'
  else
    payment_method = Spree::PaymentMethod::Check.available_on_back_end.first_or_create! do |method|
      method.name ||= 'Invoice'
      method.stores = [Spree::Store.default] if method.stores.empty?
    end
  end
  payments.create!(
    payment_method: payment_method,
    amount: total,
    source_id: source_id,
    source_type: source_type
  )
  Spree::Checkout::Advance.call(order: self)
end

#customer_addressObject



201
202
203
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 201

def customer_address
  bill_address || ship_address
end

#delivery_required?Boolean

override

Returns:

  • (Boolean)


119
120
121
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 119

def delivery_required?
  line_items.any?(&:delivery_required?)
end

#display_outstanding_balanceObject



241
242
243
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 241

def display_outstanding_balance
  Spree::Money.new(outstanding_balance, currency: currency).to_s
end

#generate_png_qr(size = 120) ⇒ Object



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 221

def generate_png_qr(size = 120)
  qrcode = RQRCode::QRCode.new(qr_data)
  qrcode.as_png(
    bit_depth: 1,
    border_modules: 1,
    color_mode: ChunkyPNG::COLOR_GRAYSCALE,
    color: 'black',
    file: nil,
    fill: 'white',
    module_px_size: 4,
    resize_exactly_to: false,
    resize_gte_to: false,
    size: size
  )
end

#generate_svg_qrObject



209
210
211
212
213
214
215
216
217
218
219
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 209

def generate_svg_qr
  qrcode = RQRCode::QRCode.new(qr_data)
  qrcode.as_svg(
    color: '000',
    shape_rendering: 'crispEdges',
    module_size: 5,
    standalone: true,
    use_path: true,
    viewbox: '0 0 20 10'
  )
end

#insufficient_stock_linesObject

override spree use this method to check stock availability & consider whether :order can continue to next state.



94
95
96
97
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 94

def insufficient_stock_lines
  checker = SpreeCmCommissioner::Stock::OrderAvailabilityChecker.new(self)
  checker.insufficient_stock_lines
end

#mark_as_archiveObject



146
147
148
149
150
151
152
153
154
155
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 146

def mark_as_archive
  blocks_canceled = begin
    cancel_blocks!
    true
  rescue StandardError
    false
  end

  update(archived_at: Time.current) if blocks_canceled
end

#order_completed?Boolean

Returns:

  • (Boolean)


205
206
207
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 205

def order_completed?
  complete? && need_confirmation? == false
end

#payment_hostObject

override spree_vpago method



246
247
248
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 246

def payment_host
  tenant&.formatted_url.presence || ENV.fetch('DEFAULT_URL_HOST')
end

#payment_required?Boolean

overrided

Returns:

  • (Boolean)


124
125
126
127
128
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 124

def payment_required?
  return false if need_confirmation?

  super
end

#purchased_from_tenant?Boolean

Returns true when the order was created under a tenant context.

Returns:

  • (Boolean)


197
198
199
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 197

def purchased_from_tenant?
  !tenant_id.nil?
end

#qr_dataObject



237
238
239
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 237

def qr_data
  "#{number}-#{token}"
end

#restart_checkout_flowObject

Override spree_core behavior to intentionally avoid calling ‘next!`.

Goal: keep the order state at ‘cart’ when restarting checkout, especially when seats were held during the address step.

Flow summary:

  • User goes from cart -> address: we hold seats.

  • User navigates back from address: we call this method to cancel the holds. We do NOT call ‘next!` here; otherwise the order state machine would trigger `hold_blocks!` again and re-hold seats unnecessarily.



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 70

def restart_checkout_flow
  ActiveRecord::Base.transaction do
    cancel_blocks! if should_manage_blocks?
    log_state_changes(state_name: 'cart', old_state: state, new_state: 'cart')
    update_columns( # rubocop:disable Rails/SkipsModelValidations
      state: 'cart',
      updated_at: Time.current
    )
  end
rescue StandardError => e
  CmAppLogger.error(
    label: 'SpreeCmCommissioner::OrderDecorator#restart_checkout_flow failed',
    data: {
      order_id: id,
      error_class: e.class.name,
      error_message: e.message,
      backtrace: e.backtrace&.first(5)&.join("\n")
    }
  )
  raise
end

#subscription?Boolean

Returns:

  • (Boolean)


192
193
194
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 192

def subscription?
  subscription.present?
end

#ticket_seller_user?Boolean

Returns:

  • (Boolean)


99
100
101
102
103
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 99

def ticket_seller_user?
  return false if user.nil?

  user.has_spree_role?('ticket_seller')
end

#valid_promotion_idsObject

overrided avoid raise error when source_id is nil. github.com/channainfo/commissioner/pull/843



160
161
162
163
164
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 160

def valid_promotion_ids
  all_adjustments.eligible.nonzero.promotion
                 .where.not(source_id: nil)
                 .map { |a| a.source.promotion_id }.uniq
end