Module: SpreeCmCommissioner::OrderDecorator
- Defined in:
- app/models/spree_cm_commissioner/order_decorator.rb
Class Method Summary collapse
-
.prepended(base) ⇒ Object
rubocop:disable Metrics/MethodLength.
Instance Method Summary collapse
- #any_app_only_products? ⇒ Boolean
-
#associate_user!(user, override_email = true) ⇒ Object
overrided add phone_number trigger when update customer detail.
-
#canceled_by(user, cancellation_reason: nil) ⇒ Object
override to allow storing cancellation reason in one DB write.
-
#collect_payment_methods(store = nil) ⇒ Object
override.
- #collect_payment_methods_for_early_adopter(store = nil) ⇒ Object
-
#connected_line_item_ids(direction: nil) ⇒ Object
Returns arrays of connected line_item IDs grouped by connected_trip_id.
-
#create_default_payment_if_eligble ⇒ Object
assume check is default payment method for subscription.
- #customer_address ⇒ Object
-
#delivery_required? ⇒ Boolean
override.
- #display_outstanding_balance ⇒ Object
- #generate_png_qr(size = 120) ⇒ Object
- #generate_svg_qr ⇒ Object
-
#insufficient_stock_lines ⇒ Object
override spree use this method to check stock availability & consider whether :order can continue to next state.
- #jwt_qr_data ⇒ Object
- #mark_as_archive ⇒ Object
- #order_completed? ⇒ Boolean
- #payment_fulfilled? ⇒ Boolean
-
#payment_host ⇒ Object
override spree_vpago method.
-
#payment_required? ⇒ Boolean
overrided.
-
#purchased_from_tenant? ⇒ Boolean
Returns true when the order was created under a tenant context.
- #qr_data ⇒ Object
-
#restart_checkout_flow ⇒ Object
override spree_core behavior to intentionally avoid calling ‘next!`.
- #subscription? ⇒ Boolean
- #ticket_seller_user? ⇒ Boolean
-
#valid_promotion_ids ⇒ Object
overrided avoid raise error when source_id is nil.
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 59 60 61 |
# 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::OrderHoldable 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. :preload_main_trip_ids, :array, default: [] base. :order_options, :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.has_many :audit_events, class_name: 'SpreeCmCommissioner::AuditEvent', as: :auditable 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
#any_app_only_products? ⇒ Boolean
150 151 152 153 154 155 156 |
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 150 def any_app_only_products? if products.loaded? products.any?(&:purchasable_on_app?) else products.exists?(purchasable_on: :app) end end |
#associate_user!(user, override_email = true) ⇒ Object
overrided add phone_number trigger when update customer detail
161 162 163 164 165 166 167 168 169 170 171 172 |
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 161 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 |
#canceled_by(user, cancellation_reason: nil) ⇒ Object
override to allow storing cancellation reason in one DB write
64 65 66 67 68 69 70 71 72 73 74 |
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 64 def canceled_by(user, cancellation_reason: nil) transaction do cancel! update_columns( # rubocop:disable Rails/SkipsModelValidations canceler_id: user.id, canceled_at: Time.current, internal_note: cancellation_reason ) end end |
#collect_payment_methods(store = nil) ⇒ Object
override
126 127 128 129 130 131 |
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 126 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
133 134 135 136 |
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 133 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 |
#connected_line_item_ids(direction: nil) ⇒ Object
Returns arrays of connected line_item IDs grouped by connected_trip_id. Example: [[1,2,3], [4,5], [6]]
Line items with the same connected_trip_id are grouped together. Line items without a group_id are returned as singletons.
287 288 289 290 291 292 293 294 |
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 287 def connected_line_item_ids(direction: nil) scoped = line_items scoped = scoped.select { |li| li.direction == direction } if direction.present? scoped.group_by { |li| li.connected_trip_id || li.id } .values .map { |group| group.map(&:id).sort } end |
#create_default_payment_if_eligble ⇒ Object
assume check is default payment method for subscription
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 |
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 195 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_address ⇒ Object
229 230 231 |
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 229 def customer_address bill_address || ship_address end |
#delivery_required? ⇒ Boolean
override
139 140 141 |
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 139 def delivery_required? line_items.any?(&:delivery_required?) end |
#display_outstanding_balance ⇒ Object
273 274 275 |
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 273 def display_outstanding_balance Spree::Money.new(outstanding_balance, currency: currency).to_s end |
#generate_png_qr(size = 120) ⇒ Object
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 |
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 249 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_qr ⇒ Object
237 238 239 240 241 242 243 244 245 246 247 |
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 237 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_lines ⇒ Object
override spree use this method to check stock availability & consider whether :order can continue to next state.
114 115 116 117 |
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 114 def insufficient_stock_lines checker = SpreeCmCommissioner::Stock::OrderAvailabilityChecker.new(self) checker.insufficient_stock_lines end |
#jwt_qr_data ⇒ Object
269 270 271 |
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 269 def jwt_qr_data SpreeCmCommissioner::Orders::JwtToken::Generate.call(order: self).value[:token] end |
#mark_as_archive ⇒ Object
174 175 176 177 178 179 180 181 182 183 |
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 174 def mark_as_archive released = begin release_order_holds! true rescue StandardError false end update(archived_at: Time.current) if released end |
#order_completed? ⇒ Boolean
233 234 235 |
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 233 def order_completed? complete? && need_confirmation? == false end |
#payment_fulfilled? ⇒ Boolean
108 109 110 |
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 108 def payment_fulfilled? payment_state.present? && payment_state == 'paid' end |
#payment_host ⇒ Object
override spree_vpago method
278 279 280 |
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 278 def payment_host tenant&.formatted_url.presence || ENV.fetch('DEFAULT_URL_HOST') end |
#payment_required? ⇒ Boolean
overrided
144 145 146 147 148 |
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 144 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.
225 226 227 |
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 225 def purchased_from_tenant? !tenant_id.nil? end |
#qr_data ⇒ Object
265 266 267 |
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 265 def qr_data "#{number}-#{token}" end |
#restart_checkout_flow ⇒ Object
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_order_holds` again and re-hold seats unnecessarily.
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 86 def restart_checkout_flow ActiveRecord::Base.transaction do release_order_holds! 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., backtrace: e.backtrace&.first(5)&.join("\n") } ) raise end |
#subscription? ⇒ Boolean
220 221 222 |
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 220 def subscription? subscription.present? end |
#ticket_seller_user? ⇒ Boolean
119 120 121 122 123 |
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 119 def ticket_seller_user? return false if user.nil? user.has_spree_role?('ticket_seller') end |
#valid_promotion_ids ⇒ Object
overrided avoid raise error when source_id is nil. github.com/channainfo/commissioner/pull/843
188 189 190 191 192 |
# File 'app/models/spree_cm_commissioner/order_decorator.rb', line 188 def valid_promotion_ids all_adjustments.eligible.nonzero.promotion .where.not(source_id: nil) .map { |a| a.source.promotion_id }.uniq end |