spree_cm_commissioner 2.1.6 → 2.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/app/controllers/spree/admin/product_completion_steps_controller.rb +3 -2
  4. data/app/controllers/spree/api/v2/tenant/line_items_controller.rb +28 -0
  5. data/app/interactors/spree_cm_commissioner/pin_code_creator.rb +11 -1
  6. data/app/interactors/spree_cm_commissioner/pin_code_sender.rb +1 -0
  7. data/app/interactors/spree_cm_commissioner/sms.rb +1 -1
  8. data/app/jobs/spree_cm_commissioner/sms_pin_code_job.rb +1 -1
  9. data/app/models/spree_cm_commissioner/block.rb +4 -0
  10. data/app/models/spree_cm_commissioner/line_item_decorator.rb +13 -3
  11. data/app/models/spree_cm_commissioner/oauth_application_decorator.rb +4 -0
  12. data/app/models/spree_cm_commissioner/pin_code.rb +2 -0
  13. data/app/models/spree_cm_commissioner/product_completion_step.rb +37 -0
  14. data/app/models/spree_cm_commissioner/product_completion_steps/social_entry_url.rb +17 -0
  15. data/app/models/spree_cm_commissioner/seat_layout.rb +5 -0
  16. data/app/overrides/spree/admin/oauth_applications/_form/tenant_fields.html.erb.deface +6 -0
  17. data/app/views/spree/admin/product_completion_steps/_form.html.erb +1 -1
  18. data/config/locales/en.yml +4 -0
  19. data/config/locales/km.yml +9 -1
  20. data/config/routes.rb +6 -1
  21. data/db/migrate/20250930094228_add_application_id_to_cm_pin_codes.rb +10 -0
  22. data/db/migrate/20250930100657_add_settings_to_spree_oauth_applications.rb +7 -0
  23. data/lib/spree_cm_commissioner/test_helper/factories/pin_code_factory.rb +4 -0
  24. data/lib/spree_cm_commissioner/version.rb +1 -1
  25. metadata +5 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a95912c38ef5e186747ac34d70d48d7f08db4fc4f4c69412f32706f3d72fd678
4
- data.tar.gz: ca0e0437c30f7ecf6a0fb6a91aa8186126c02e8e671c9b98249261bd2c61ffea
3
+ metadata.gz: b7e5168cb588dc6b931bee2b2711b37886b364323bf2e7215390fde1e46479b8
4
+ data.tar.gz: ed7571aca12c59e7385bd7e34fcde1105b0c8c04484d652bc5c4974f4c90e2ca
5
5
  SHA512:
6
- metadata.gz: c4fcf779134f8a8a8e5e94d7da2796899f1c32efe9e588e7fe314ddda4584b5c9c2c22766c7e3860d5a2b1ace1989ee6077f2e50b43fe9d879b2885b32033e00
7
- data.tar.gz: 255a2d1f41917634ef14529eaa5e35d648dcbe748b87191f3c4457d8ab544dac50cef02b6e68f58000aae2c8b71dbb65a91e46a71576b3416ff1dc334085427a
6
+ metadata.gz: e744361324c16633f8e3648c90b5af642e9deae632e3e9d92681c6d05ffdeca616663b7c535f8ea0f530d640232d4498389f7109d668d92f0f3fcc21afc57038
7
+ data.tar.gz: c428e0893d04a933352fe9965f3f1f0e3b270715652f598bbcdf2b12dbf30cb15194eb5e3e5adff6e321d532d0faddae9e40f881060f3cc6cce403031bbbb457
data/Gemfile.lock CHANGED
@@ -34,7 +34,7 @@ GIT
34
34
  PATH
35
35
  remote: .
36
36
  specs:
37
- spree_cm_commissioner (2.1.6)
37
+ spree_cm_commissioner (2.1.7)
38
38
  activerecord-multi-tenant
39
39
  activerecord_json_validator (~> 2.1, >= 2.1.3)
40
40
  aws-sdk-cloudfront
@@ -7,7 +7,8 @@ module Spree
7
7
 
8
8
  def load_step_types
9
9
  @step_types = [
10
- 'SpreeCmCommissioner::ProductCompletionSteps::ChatraceTelegram'
10
+ 'SpreeCmCommissioner::ProductCompletionSteps::ChatraceTelegram',
11
+ 'SpreeCmCommissioner::ProductCompletionSteps::SocialEntryUrl'
11
12
  ]
12
13
  end
13
14
 
@@ -21,7 +22,7 @@ module Spree
21
22
 
22
23
  # @overrided
23
24
  def collection
24
- parent.product_completion_steps
25
+ parent.product_completion_steps.order(:position)
25
26
  end
26
27
 
27
28
  # @overrided
@@ -18,6 +18,34 @@ module Spree
18
18
  render_serialized_payload { serialize_resource(line_item) }
19
19
  end
20
20
 
21
+ def mark_as_completed # rubocop:disable Metrics/PerceivedComplexity
22
+ line_item = Spree::LineItem.find(params[:id])
23
+
24
+ metadata = (line_item.public_metadata || {}).deep_transform_keys(&:to_s)
25
+ steps = metadata['completion_steps']
26
+
27
+ if steps.present? && steps.is_a?(Array)
28
+ step = steps.find { |s| s['position'] == 1 } || steps[0]
29
+
30
+ if step
31
+ if step['action_url'].present?
32
+ step['completed'] = true
33
+ metadata['completion_steps'] = steps
34
+ line_item.public_metadata = metadata
35
+ line_item.save!
36
+
37
+ render_serialized_payload { serialize_resource(line_item) }
38
+ else
39
+ render_error_payload('Action url is nil, cannot update to completed')
40
+ end
41
+ else
42
+ render_error_payload('Step with position 1 not found')
43
+ end
44
+ else
45
+ render_error_payload('completion_steps does not exist for this line_item')
46
+ end
47
+ end
48
+
21
49
  private
22
50
 
23
51
  def allowed_sort_attributes
@@ -2,8 +2,9 @@ module SpreeCmCommissioner
2
2
  class PinCodeCreator < BaseInteractor
3
3
  def call
4
4
  set_contact
5
+ set_application
5
6
 
6
- attrs = { contact: context.contact, contact_type: context.contact_type, type: context.type }
7
+ attrs = { contact: context.contact, contact_type: context.contact_type, type: context.type, application: context.application }
7
8
  new_pin_code = SpreeCmCommissioner::PinCode.new(attrs)
8
9
 
9
10
  if new_pin_code.save
@@ -29,5 +30,14 @@ module SpreeCmCommissioner
29
30
  context.contact_type = :phone_number
30
31
  end
31
32
  end
33
+
34
+ def set_application
35
+ return nil if context.tenant.blank?
36
+
37
+ context.application = Spree::OauthApplication.find_by(tenant_id: context.tenant.id)
38
+ context.fail!(message: I18n.t('pincode_creator.application_not_found')) if context.application.nil?
39
+
40
+ context.application
41
+ end
32
42
  end
33
43
  end
@@ -18,6 +18,7 @@ module SpreeCmCommissioner
18
18
 
19
19
  def send_sms
20
20
  options = {
21
+ from: context.pin_code&.application&.sms_sender_id,
21
22
  to: context.pin_code.contact,
22
23
  body: I18n.t('pincode_sender.sms.body', code: context.pin_code.code, readable_type: context.pin_code.readable_type)
23
24
  }
@@ -48,7 +48,7 @@ module SpreeCmCommissioner
48
48
  end
49
49
 
50
50
  def from_number
51
- context.from || ENV['SMS_SENDER_ID'].presence || 'SMS Info'
51
+ context.from.presence || ENV['SMS_SENDER_ID'].presence || 'SMS Info'
52
52
  end
53
53
 
54
54
  def sanitize(number)
@@ -1,6 +1,6 @@
1
1
  module SpreeCmCommissioner
2
2
  class SmsPinCodeJob < SpreeCmCommissioner::SmsJob
3
- # options = { to: xxxx, body: xxxx }
3
+ # options = { from: xxxx, to: xxxx, body: xxxx }
4
4
  def perform(options)
5
5
  SpreeCmCommissioner::Sms.call(options)
6
6
  end
@@ -13,6 +13,10 @@ module SpreeCmCommissioner
13
13
  belongs_to :seat_layout, class_name: 'SpreeCmCommissioner::SeatLayout', optional: false
14
14
  belongs_to :variant, class_name: 'Spree::Variant', optional: true
15
15
 
16
+ has_many :all_reserved_blocks, class_name: 'SpreeCmCommissioner::ReservedBlock', dependent: :destroy
17
+ has_many :reserved_blocks, -> { reserved }, class_name: 'SpreeCmCommissioner::ReservedBlock', dependent: :destroy
18
+ has_many :active_on_hold_reserved_blocks, -> { reserved_or_on_hold }, class_name: 'SpreeCmCommissioner::ReservedBlock', dependent: :destroy
19
+
16
20
  validates :label, presence: true, if: :label_required?
17
21
  validates :width, presence: true, numericality: { greater_than: 0 }
18
22
  validates :height, presence: true, numericality: { greater_than: 0 }
@@ -26,6 +26,8 @@ module SpreeCmCommissioner
26
26
 
27
27
  base.before_save :update_vendor_id
28
28
 
29
+ base.after_commit :persist_completion_steps_to_public_metadata, on: :create
30
+
29
31
  base.before_create :add_due_date, if: :subscription?
30
32
 
31
33
  base.validate :ensure_not_exceed_max_quantity_per_order, if: -> { variant&.max_quantity_per_order.present? }
@@ -196,9 +198,7 @@ module SpreeCmCommissioner
196
198
  end
197
199
 
198
200
  def completion_steps
199
- @completion_steps ||= product_completion_steps.map do |completion_step|
200
- completion_step.construct_hash(line_item: self)
201
- end
201
+ public_metadata[:completion_steps] || []
202
202
  end
203
203
 
204
204
  # override
@@ -217,6 +217,16 @@ module SpreeCmCommissioner
217
217
 
218
218
  private
219
219
 
220
+ def persist_completion_steps_to_public_metadata
221
+ steps = product_completion_steps.order(:position).map do |pcs|
222
+ pcs.construct_hash(line_item: self).except(:completed).merge(
223
+ id: pcs.id,
224
+ completed: false
225
+ )
226
+ end
227
+ update_column(:public_metadata, (public_metadata || {}).merge(completion_steps: steps)) # rubocop:disable Rails/SkipsModelValidations
228
+ end
229
+
220
230
  def ensure_not_exceed_max_quantity_per_order
221
231
  errors.add(:quantity, I18n.t('line_item.validation.exceeded_max_quantity_per_order')) if quantity > variant.max_quantity_per_order
222
232
  end
@@ -2,6 +2,10 @@ module SpreeCmCommissioner
2
2
  module OauthApplicationDecorator
3
3
  def self.prepended(base)
4
4
  base.belongs_to :tenant, class_name: 'SpreeCmCommissioner::Tenant'
5
+
6
+ # treat a key inside a JSONB column like a normal Rails attribute,
7
+ # with getter/setter methods
8
+ base.store_accessor :settings, :sms_sender_id
5
9
  end
6
10
  end
7
11
  end
@@ -18,6 +18,8 @@ module SpreeCmCommissioner
18
18
  PIN_CODE_MISMATCHED = 'not_match'.freeze
19
19
  PIN_CODE_OK = 'ok'.freeze
20
20
 
21
+ belongs_to :application, class_name: 'Spree::OauthApplication', optional: true
22
+
21
23
  def check?(code)
22
24
  return PIN_CODE_EXPIRED if expired?
23
25
  return PIN_CODE_ATTEMPT_REACHED if number_of_attempt_reached?
@@ -4,6 +4,10 @@ module SpreeCmCommissioner
4
4
 
5
5
  belongs_to :product, class_name: '::Spree::Product', optional: false
6
6
 
7
+ after_save :propagate_completion_steps_to_line_items
8
+
9
+ after_destroy_commit :propagate_completion_steps_to_line_items
10
+
7
11
  def action_url_for(_line_item)
8
12
  nil
9
13
  end
@@ -23,5 +27,38 @@ module SpreeCmCommissioner
23
27
  completed: completed?(line_item)
24
28
  }
25
29
  end
30
+
31
+ private
32
+
33
+ def propagate_completion_steps_to_line_items
34
+ product.line_items.find_each do |line_item|
35
+ propagate_to_line_item(line_item)
36
+ end
37
+ end
38
+
39
+ def propagate_to_line_item(line_item)
40
+ current_metadata = line_item.reload.public_metadata || {}
41
+ stored_steps = Array(current_metadata[:completion_steps])
42
+
43
+ fresh_steps = product.product_completion_steps.order(:position).map do |pcs|
44
+ base_attrs = pcs.construct_hash(line_item: line_item).except(:completed)
45
+
46
+ previous =
47
+ stored_steps.find { |s| s[:id] == pcs.id } ||
48
+ stored_steps.find { |s| s[:type] == pcs.type&.underscore && s[:position] == pcs.position }
49
+
50
+ completed_flag = previous&.dig(:completed) ? true : false
51
+
52
+ base_attrs.merge(
53
+ id: pcs.id,
54
+ completed: completed_flag
55
+ )
56
+ end
57
+
58
+ line_item.update_column( # rubocop:disable Rails/SkipsModelValidations
59
+ :public_metadata,
60
+ current_metadata.merge(completion_steps: fresh_steps)
61
+ )
62
+ end
26
63
  end
27
64
  end
@@ -0,0 +1,17 @@
1
+ module SpreeCmCommissioner
2
+ module ProductCompletionSteps
3
+ class SocialEntryUrl < ProductCompletionStep
4
+ # eg. https://t.me/ThePlatformKHBot?start=bookmeplus
5
+ preference :entry_point_link, :string
6
+
7
+ # override
8
+ def action_url_for(_line_item)
9
+ preferred_entry_point_link.presence
10
+ end
11
+
12
+ def completed?(_line_item)
13
+ false
14
+ end
15
+ end
16
+ end
17
+ end
@@ -6,6 +6,11 @@ module SpreeCmCommissioner
6
6
  has_many :top_level_blocks, -> { where(seat_section_id: nil) }, class_name: 'SpreeCmCommissioner::Block', dependent: :destroy
7
7
  has_many :section_blocks, -> { where.not(seat_section_id: nil) }, class_name: 'SpreeCmCommissioner::Block' # destroy is handled by seat_section
8
8
 
9
+ has_many :reserved_blocks, class_name: 'SpreeCmCommissioner::ReservedBlock', through: :blocks, source: :all_reserved_blocks
10
+ has_many :active_on_hold_reserved_blocks, class_name: 'SpreeCmCommissioner::ReservedBlock',
11
+ through: :blocks,
12
+ source: :active_on_hold_reserved_blocks
13
+
9
14
  belongs_to :layoutable, polymorphic: true
10
15
 
11
16
  enum status: {
@@ -5,3 +5,9 @@
5
5
  <%= f.collection_select :tenant_id, SpreeCmCommissioner::Tenant.all, :id, :name, { prompt: Spree.t(:select_tenant) }, { class: 'form-control select2' } %>
6
6
  <%= f.error_message_on :tenant_id %>
7
7
  <% end %>
8
+
9
+ <%= f.field_container :sms_sender_id, 'data-hook' => "oauth_application_settings_sms_sender_id" do %>
10
+ <%= f.label :sms_sender_id, raw('SMS Sender ID (optional)') %>
11
+ <%= f.text_field :sms_sender_id, class: 'form-control' %>
12
+ <%= f.error_message_on :sms_sender_id %>
13
+ <% end %>
@@ -8,7 +8,7 @@
8
8
  <div class="card-body">
9
9
  <%= f.field_container :type, 'data-hook' => 'type' do %>
10
10
  <%= f.label :type, Spree.t(:type) %>
11
- <%= f.select(:type, SpreeCmCommissioner::ProductCompletionStep.descendants.map { |v| [v.to_s.demodulize, v.to_s] }, {}, { class: 'select2' }) %>
11
+ <%= f.select(:type, @step_types.map { |t| [t.demodulize, t] }, {}, { class: 'select2' }) %>
12
12
  <% end %>
13
13
 
14
14
  <%= f.field_container :title, 'data-hook' => 'title' do %>
@@ -11,9 +11,12 @@ en:
11
11
  body:
12
12
  blank: "sms content can not be blank"
13
13
  already_exist: "%{login} already exist"
14
+
14
15
  pincode_creator:
15
16
  invalid_phone_number: "Invalid phone number"
16
17
  invalid_email_address: "Invalid email address"
18
+ application_not_found: "Application not found"
19
+
17
20
  pincode_checker:
18
21
  error_type:
19
22
  not_found: "Verification Code not found!"
@@ -21,6 +24,7 @@ en:
21
24
  reached_max_attempt: "Verification Code already reach max attempt!"
22
25
  not_match: "Verification code is not valid"
23
26
  ok: "Verification code is valid"
27
+
24
28
  authenticator:
25
29
  incorrect_login: "Incorrect login"
26
30
  incorrect_password: "Incorrect password"
@@ -22,12 +22,20 @@ km:
22
22
  blank: "recipient can not be blank"
23
23
  body:
24
24
  blank: "sms content can not be blank"
25
-
26
25
  already_exist: "%{login} already exist"
27
26
 
28
27
  pincode_creator:
29
28
  invalid_phone_number: "លេខទូរសព្ទមិនត្រឹមត្រូវ"
30
29
  invalid_email_address: "អ៊ីមែលមិនត្រឹមត្រូវ"
30
+ application_not_found: "រកមិនឃើញកម្មវិធី"
31
+
32
+ pincode_checker:
33
+ error_type:
34
+ not_found: "រកមិនឃើញលេខសម្ងាត់"
35
+ expired: "លេខសម្ងាត់បានផុតកំណត់"
36
+ reached_max_attempt: "បានដល់កម្រិតអតិបរមា"
37
+ not_match: "លេខសម្ងាត់មិនត្រឹមត្រូវ"
38
+ ok: "លេខសម្ងាត់ត្រឹមត្រូវ"
31
39
 
32
40
  authenticator:
33
41
  incorrect_login: "ពត៌មានមិនត្រឹមត្រូវ"
data/config/routes.rb CHANGED
@@ -531,7 +531,12 @@ Spree::Core::Engine.add_routes do
531
531
  resources :cart_payment_method_groups, only: %i[index]
532
532
  resource :s3_signed_urls
533
533
  resource :profile_images, only: %i[update destroy]
534
- resources :line_items, only: %i[index show]
534
+ resources :line_items, only: %i[index show update] do
535
+ member do
536
+ patch :mark_as_completed
537
+ end
538
+ end
539
+
535
540
  resources :guest_card_classes
536
541
  resources :tickets, only: :index
537
542
 
@@ -0,0 +1,10 @@
1
+ class AddApplicationIdToCmPinCodes < ActiveRecord::Migration[7.0]
2
+ def change
3
+ unless column_exists?(:cm_pin_codes, :application_id)
4
+ add_reference :cm_pin_codes,
5
+ :application,
6
+ foreign_key: { to_table: :spree_oauth_applications },
7
+ index: true
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,7 @@
1
+ class AddSettingsToSpreeOauthApplications < ActiveRecord::Migration[7.0]
2
+ def change
3
+ unless column_exists?(:spree_oauth_applications, :settings, :jsonb)
4
+ add_column :spree_oauth_applications, :settings, :jsonb, default: {}, null: false
5
+ end
6
+ end
7
+ end
@@ -18,5 +18,9 @@ FactoryBot.define do
18
18
  contact_type { :phone_number }
19
19
  sequence(:contact) { |n| "087420441#{n}" }
20
20
  end
21
+
22
+ trait :with_application do
23
+ association :application, factory: :oauth_application
24
+ end
21
25
  end
22
26
  end
@@ -1,5 +1,5 @@
1
1
  module SpreeCmCommissioner
2
- VERSION = '2.1.6'.freeze
2
+ VERSION = '2.1.7'.freeze
3
3
 
4
4
  module_function
5
5
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spree_cm_commissioner
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.6
4
+ version: 2.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - You
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-09-29 00:00:00.000000000 Z
11
+ date: 2025-10-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: spree
@@ -1423,6 +1423,7 @@ files:
1423
1423
  - app/models/spree_cm_commissioner/price_decorator.rb
1424
1424
  - app/models/spree_cm_commissioner/product_completion_step.rb
1425
1425
  - app/models/spree_cm_commissioner/product_completion_steps/chatrace_telegram.rb
1426
+ - app/models/spree_cm_commissioner/product_completion_steps/social_entry_url.rb
1426
1427
  - app/models/spree_cm_commissioner/product_decorator.rb
1427
1428
  - app/models/spree_cm_commissioner/product_dynamic_field.rb
1428
1429
  - app/models/spree_cm_commissioner/product_google_wallet.rb
@@ -2753,6 +2754,8 @@ files:
2753
2754
  - db/migrate/20250911174607_add_metadata_columns_to_cm_vehicles.rb
2754
2755
  - db/migrate/20250911174653_add_metadata_columns_to_cm_trips.rb
2755
2756
  - db/migrate/20250912084944_add_send_type_to_sms_log.rb
2757
+ - db/migrate/20250930094228_add_application_id_to_cm_pin_codes.rb
2758
+ - db/migrate/20250930100657_add_settings_to_spree_oauth_applications.rb
2756
2759
  - docker-compose.yml
2757
2760
  - docs/option_types/attr_types.md
2758
2761
  - docs/private_key.pem