spree_cm_commissioner 1.13.0 → 1.14.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3da0bd043e4ceca1f57afecc1bab6fbc58c960ba296f7fffa42b449a2475f8f8
4
- data.tar.gz: 974c8e19e026fa90254594447a9735be039371ae6d0bc11a24c9cdf3b86dfd8c
3
+ metadata.gz: a83f128539c20da0667aaa913954b8d686df38054b90ea51ede36b2967a96c4b
4
+ data.tar.gz: 46fa67f9aff722e83efd60ae52bb640f5ba9b2576294625a3c07093cbf0c2784
5
5
  SHA512:
6
- metadata.gz: 4b1d418758d9880e50dd1481b095f4cad76cc106ca0a950b694d2a87c053bf7f48655029c52939f33bf099db0a7d84048f0482d488a20ac720f1b6f8015a687e
7
- data.tar.gz: 93b3ffb94424ba4a4ed46e5cde3303dc33c54a58417dd1a0750a5cb56d3638778d1fa5ceb75cf812617c33e12ae3c38c6402b7719ddfa53b2ce9567a8bb860e4
6
+ metadata.gz: d48ff6f2945c262955121a7f7144c5fc4ad53afa23bb2b093baaefd985346276a60b82de985b1912ec5a8fb64e6e86d37eb163638c2261446c2f85945165c3df
7
+ data.tar.gz: 7e21994489d8d36559a632a0008a92ecf9902c95be865190624173b89e1c8ad6146f405744971dbd448935cf9a9557b60401f34b6d211ce833eca61880082719
data/Gemfile.lock CHANGED
@@ -34,7 +34,7 @@ GIT
34
34
  PATH
35
35
  remote: .
36
36
  specs:
37
- spree_cm_commissioner (1.13.0)
37
+ spree_cm_commissioner (1.14.0)
38
38
  activerecord-multi-tenant
39
39
  activerecord_json_validator (~> 2.1, >= 2.1.3)
40
40
  aws-sdk-cloudfront
@@ -16,9 +16,12 @@ module Spree
16
16
  return render_error(:fully_claimed) if @invite_guest.fully_claimed?
17
17
 
18
18
  guest = @line_item.guests.new(guest_params)
19
+ guest.event_id = @invite_guest.event_id
19
20
 
20
21
  if guest.save
21
22
  @invite_guest.update(claimed_status: :claimed) if @line_item.guests.count == @invite_guest.quantity
23
+ send_guest_claimed_invitation_telegram_alert_to_vendor(guest)
24
+
22
25
  render json: SpreeCmCommissioner::V2::Storefront::GuestSerializer.new(guest.reload).serializable_hash
23
26
  else
24
27
  render_error_payload(guest.errors.full_messages.to_sentence)
@@ -27,6 +30,23 @@ module Spree
27
30
 
28
31
  private
29
32
 
33
+ def send_guest_claimed_invitation_telegram_alert_to_vendor(guest)
34
+ title = 'šŸ“£ --- [NEW GUEST CLAIMED INVITATION] ---' # Style/StringLiterals
35
+ chat_id = guest.event.vendor.preferred_telegram_chat_id
36
+ return if chat_id.blank?
37
+
38
+ factory = SpreeCmCommissioner::InviteGuestClaimedTelegramMessageFactory.new(
39
+ title: title,
40
+ order: @invite_guest.order,
41
+ vendor: guest.event.vendor
42
+ )
43
+ SpreeCmCommissioner::TelegramNotificationSenderJob.perform_later(
44
+ chat_id: chat_id,
45
+ message: factory.message,
46
+ parse_mode: factory.parse_mode
47
+ )
48
+ end
49
+
30
50
  def load_invite_guest_by_token
31
51
  @invite_guest = SpreeCmCommissioner::InviteGuest.find_by(token: params[:id])
32
52
  rescue ActiveRecord::RecordNotFound
@@ -0,0 +1,120 @@
1
+ # šŸŽŸļø --- [TICKET CLAIMED] ---
2
+ #
3
+ # Order Number:
4
+ # <code>R621016753</code>
5
+ #
6
+ # āœ… <b>Ticket Successfully Claimed!</b>
7
+ #
8
+ # [ x1 ]
9
+ # <b>5km Running Ticket</b>
10
+ # <i>šŸ‘‰ Distance: 5km, T-shirt: M</i>
11
+ # <i>šŸ—“ļø Nov 15, 2023</i>
12
+ # <i>šŸŖ Temple Run with Sai</i>
13
+ #
14
+ # [ x2 ]
15
+ # <b>5km Running Ticket</b>
16
+ # <i>šŸ‘‰ Distance: 5km, T-shirt: S</i>
17
+ # <i>šŸ—“ļø Nov 15, 2023 -> Nov 17, 2023</i>
18
+ # <i>šŸŖ Temple Run with Sai</i>
19
+ #
20
+ # <b>šŸ™ Claimed By</b>
21
+ # Name: Vaneath Awesome
22
+ # Tel: <code>+85570760548</code>
23
+ # Email: <code>admin_dev@cm.com</code>
24
+
25
+ module SpreeCmCommissioner
26
+ class InviteGuestClaimedTelegramMessageFactory < TelegramMessageFactory
27
+ attr_reader :order, :vendor, :show_details_link
28
+
29
+ def initialize(title:, order:, subtitle: nil, show_details_link: nil, vendor: nil)
30
+ @order = order
31
+ @vendor = vendor
32
+ @show_details_link = show_details_link || false
33
+
34
+ super(title: title, subtitle: subtitle)
35
+ end
36
+
37
+ def selected_line_items
38
+ return order.line_items.for_vendor(vendor) if vendor.present?
39
+
40
+ order.line_items
41
+ end
42
+
43
+ # override
44
+ def body
45
+ text = []
46
+ text << "Order Number:\n<code>#{order.number}</code>\n"
47
+ text << "\nāœ… <b>Ticket Successfully Claimed!</b>\n"
48
+ text << selected_line_items.map { |item| line_item_content(item) }.compact.join("\n\n")
49
+ text.compact.join("\n")
50
+ end
51
+
52
+ def line_item_content(line_item)
53
+ text = []
54
+
55
+ text << bold(line_item.product.name.to_s)
56
+ text << "Quantity: #{line_item.quantity}"
57
+ text << italic("šŸ‘‰ #{line_item.options_text}") if line_item.options_text.present?
58
+ text << italic(pretty_date_for(line_item)) if pretty_date_for(line_item).present?
59
+ text << italic("šŸŖ #{line_item.vendor.name}") if line_item.vendor&.name.present? && vendor.blank?
60
+
61
+ text.compact.join("\n")
62
+ end
63
+
64
+ def pretty_date_for(line_item)
65
+ return nil unless line_item.date_present?
66
+
67
+ from_date = pretty_date(line_item.from_date)
68
+ to_date = pretty_date(line_item.to_date)
69
+
70
+ if from_date == to_date
71
+ "šŸ—“ļø #{from_date}"
72
+ else
73
+ "šŸ—“ļø #{from_date} -> #{to_date}"
74
+ end
75
+ end
76
+
77
+ # override
78
+ def footer
79
+ text = []
80
+
81
+ text << bold('šŸ™ Claimed By')
82
+ text << "Name: #{order.name}"
83
+ text << "Tel: #{inline_code(order.intel_phone_number || order.phone_number)}"
84
+ text << "Email: #{inline_code(order.email)}" if order.email.present?
85
+
86
+ if show_details_link && order.guests.any?
87
+ text << ''
88
+ text << 'View Tickets:'
89
+ text += generate_guests_links(order.guests)
90
+ end
91
+
92
+ text.compact.join("\n")
93
+ end
94
+
95
+ # Result:
96
+ # | No. A24 | No. A24 |
97
+ # | No. A24 | No. A24 |
98
+ # | No. A24 | No. A24 |
99
+ # | No. A24 | No. A24 |
100
+ # | No. A24 | No. A24 |
101
+ # | No. A24 |
102
+ def generate_guests_links(guests, guests_per_row = 2)
103
+ rows = (guests.size.to_f / guests_per_row).ceil
104
+ formatted_rows = []
105
+
106
+ rows.times do |i|
107
+ row_guests = guests.slice(i * guests_per_row, guests_per_row)
108
+ formatted_row = row_guests.map do |guest|
109
+ button_label = guest.seat_number.present? ? "No. #{guest.seat_number}" : "No. #{guest.formatted_bib_number || 'N/A'}"
110
+ link = Rails.application.routes.url_helpers.guest_cards_url(guest.token)
111
+ "| <a href='#{link}'>#{button_label}</a>"
112
+ end.join(' ')
113
+
114
+ formatted_rows << ("#{formatted_row} |")
115
+ end
116
+
117
+ formatted_rows
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,16 @@
1
+ module SpreeCmCommissioner
2
+ module Products
3
+ module FindDecorator
4
+ # override: to return only visble products
5
+ def by_taxons(products)
6
+ return products unless taxons?
7
+
8
+ products.joins(:classifications).where(::Spree::Classification.table_name => { taxon_id: taxons, visible: true })
9
+ end
10
+ end
11
+ end
12
+ end
13
+
14
+ unless Spree::Products::Find.included_modules.include?(SpreeCmCommissioner::Products::FindDecorator)
15
+ Spree::Products::Find.prepend(SpreeCmCommissioner::Products::FindDecorator)
16
+ end
@@ -0,0 +1,12 @@
1
+ module SpreeCmCommissioner
2
+ module Transit
3
+ module TripHelper
4
+ def parse_time(time, timezone = nil)
5
+ return nil if time.blank?
6
+
7
+ formatted_time = Time.zone.parse(time.to_s)
8
+ timezone ? formatted_time.in_time_zone(timezone) : formatted_time
9
+ end
10
+ end
11
+ end
12
+ end
@@ -2,8 +2,23 @@ module SpreeCmCommissioner
2
2
  module CmsPageDecorator
3
3
  def self.prepended(base)
4
4
  base.belongs_to :tenant, class_name: 'SpreeCmCommissioner::Tenant'
5
+
6
+ base.validates :slug,
7
+ uniqueness: {
8
+ scope: %i[tenant_id deleted_at],
9
+ allow_nil: true,
10
+ case_sensitive: true
11
+ }
5
12
  end
6
13
  end
7
14
  end
8
15
 
9
- Spree::CmsPage.prepend(SpreeCmCommissioner::CmsPageDecorator) unless Spree::CmsPage.included_modules.include?(SpreeCmCommissioner::CmsPageDecorator)
16
+ unless Spree::CmsPage.included_modules.include?(SpreeCmCommissioner::CmsPageDecorator)
17
+ # remove old :slug validations
18
+ Spree::CmsPage._validators.reject! { |key, _| key == :slug }
19
+ Spree::CmsPage._validate_callbacks.each do |c|
20
+ c.filter.attributes.delete(:slug) if c.filter.respond_to?(:attributes)
21
+ end
22
+
23
+ Spree::CmsPage.prepend(SpreeCmCommissioner::CmsPageDecorator)
24
+ end
@@ -1,21 +1,23 @@
1
1
  module SpreeCmCommissioner
2
2
  class TripQuery
3
- attr_reader :origin_id, :destination_id, :travel_date
3
+ include SpreeCmCommissioner::Transit::TripHelper
4
4
 
5
- def initialize(origin_id:, destination_id:, travel_date: Time.zone.now)
5
+ attr_reader :origin_id, :destination_id, :travel_date, :params
6
+
7
+ def initialize(origin_id:, destination_id:, travel_date:, params: {})
6
8
  @origin_id = origin_id
7
9
  @destination_id = destination_id
8
10
  @travel_date = travel_date
11
+ @travel_date = Time.zone.now if travel_date.to_date == Time.zone.now.to_date
12
+ @params = params
9
13
  end
10
14
 
11
15
  def call
12
- trips = direct_trips
13
- connections = connected_trips if trips.size < 3
14
-
15
- trip_results = trips.map { |trip| SpreeCmCommissioner::TripQueryResult.new([trip]) }
16
+ return [] if travel_date.to_date < Date.current
16
17
 
17
- trip_results += connections if connections
18
- trip_results
18
+ direct_results = direct_trips.map { |trip| SpreeCmCommissioner::TripQueryResult.new([trip]) }
19
+ connected_results = connected_trips || []
20
+ direct_results + connected_results
19
21
  end
20
22
 
21
23
  def direct_trips
@@ -38,7 +40,12 @@ module SpreeCmCommissioner
38
40
  .joins('INNER JOIN cm_trip_stops AS drop_off ON drop_off.trip_id = spree_variants.id AND drop_off.stop_type = 1')
39
41
  .joins('INNER JOIN spree_vendors AS vendors ON vendors.id = spree_variants.vendor_id')
40
42
  .joins('INNER JOIN spree_products AS routes ON routes.id = spree_variants.product_id')
41
- .where('boarding.stop_id = ? AND drop_off.stop_id = ?', origin_id, destination_id)
43
+ result = result.where(vendors: { id: params[:vendor_id] }) if params[:vendor_id].present?
44
+ result = result.where('boarding.stop_id = ? AND drop_off.stop_id = ?', origin_id, destination_id)
45
+ .where('trips.departure_time > ? AND trips.departure_time <= ?',
46
+ travel_date.strftime('%H:%M:%S'),
47
+ travel_date.end_of_day.strftime('%H:%M:%S')
48
+ )
42
49
 
43
50
  result.map do |trip|
44
51
  trip_result_options = {
@@ -53,7 +60,7 @@ module SpreeCmCommissioner
53
60
  destination_id: trip[:destination_id],
54
61
  destination: trip[:destination],
55
62
  vehicle_id: trip[:vehicle_id],
56
- departure_time: trip[:departure_time],
63
+ departure_time: parse_time(trip[:departure_time]),
57
64
  duration: trip[:duration]
58
65
  }
59
66
  SpreeCmCommissioner::TripResult.new(trip_result_options)
@@ -63,17 +70,17 @@ module SpreeCmCommissioner
63
70
  def connected_trips # rubocop:disable Metrics/MethodLength
64
71
  result = SpreeCmCommissioner::TripConnection
65
72
  .joins('
66
- INNER JOIN spree_variants variant1 ON variant1.id = cm_trip_connections.from_trip_id
67
- INNER JOIN spree_variants variant2 ON variant2.id = cm_trip_connections.to_trip_id
68
- INNER JOIN spree_products AS routes1 ON routes1.id = variant1.product_id
69
- INNER JOIN spree_products AS routes2 ON routes2.id = variant2.product_id
70
- INNER JOIN cm_trips AS trip1 ON trip1.variant_id = cm_trip_connections.from_trip_id
71
- INNER JOIN cm_trips AS trip2 ON trip2.variant_id = cm_trip_connections.to_trip_id
72
- INNER JOIN cm_trip_stops trip1_origin ON trip1_origin.trip_id = variant1.id AND trip1_origin.stop_type = 0
73
- INNER JOIN cm_trip_stops trip2_origin ON trip2_origin.trip_id = variant2.id AND trip2_origin.stop_type = 0
74
- INNER JOIN cm_trip_stops trip2_destination ON trip2_destination.trip_id = variant2.id AND trip2_destination.stop_type = 1
75
- INNER JOIN spree_vendors AS vendor1 ON vendor1.id = variant1.vendor_id
76
- INNER JOIN spree_vendors AS vendor2 ON vendor2.id = variant2.vendor_id'
73
+ INNER JOIN spree_variants variant1 ON variant1.id = cm_trip_connections.from_trip_id
74
+ INNER JOIN spree_variants variant2 ON variant2.id = cm_trip_connections.to_trip_id
75
+ INNER JOIN spree_products AS routes1 ON routes1.id = variant1.product_id
76
+ INNER JOIN spree_products AS routes2 ON routes2.id = variant2.product_id
77
+ INNER JOIN cm_trips AS trip1 ON trip1.variant_id = cm_trip_connections.from_trip_id
78
+ INNER JOIN cm_trips AS trip2 ON trip2.variant_id = cm_trip_connections.to_trip_id
79
+ INNER JOIN cm_trip_stops trip1_origin ON trip1_origin.trip_id = variant1.id AND trip1_origin.stop_type = 0
80
+ INNER JOIN cm_trip_stops trip2_origin ON trip2_origin.trip_id = variant2.id AND trip2_origin.stop_type = 0
81
+ INNER JOIN cm_trip_stops trip2_destination ON trip2_destination.trip_id = variant2.id AND trip2_destination.stop_type = 1
82
+ INNER JOIN spree_vendors AS vendor1 ON vendor1.id = variant1.vendor_id
83
+ INNER JOIN spree_vendors AS vendor2 ON vendor2.id = variant2.vendor_id'
77
84
  )
78
85
  .select('cm_trip_connections.id AS id,
79
86
  trip1.variant_id AS trip1_id,
@@ -97,8 +104,11 @@ module SpreeCmCommissioner
97
104
  trip2_origin.stop_name AS trip2_origin,
98
105
  trip2_destination.stop_name AS trip2_destination,
99
106
  vendor2.name AS trip2_vendor_name'
100
- ).where('trip1_origin.stop_id = ? AND trip2_destination.stop_id = ?', origin_id, destination_id
101
- ).uniq
107
+ ).where('trip1_origin.stop_id = ? AND trip2_destination.stop_id = ?', origin_id, destination_id)
108
+ result = result.where('vendor1.id = ? OR vendor2.id = ?', params[:vendor_id], params[:vendor_id]) if params[:vendor_id].present?
109
+ result = result.where('trip1.departure_time > ? AND trip1.departure_time <= ?', travel_date.strftime('%H:%M:%S'),
110
+ travel_date.end_of_day.strftime('%H:%M:%S')
111
+ ).uniq
102
112
 
103
113
  return [] if result.blank?
104
114
 
@@ -113,7 +123,7 @@ module SpreeCmCommissioner
113
123
  trip_id: trip[:trip1_id],
114
124
  origin_id: trip[:trip1_origin_id],
115
125
  destination_id: trip[:trip1_destination_id],
116
- departure_time: trip[:trip1_departure_time],
126
+ departure_time: parse_time(trip[:trip1_departure_time]),
117
127
  duration: trip[:trip1_duration],
118
128
  vendor_name: trip[:trip1_vendor_name],
119
129
  route_name: trip[:route1_name],
@@ -126,7 +136,7 @@ module SpreeCmCommissioner
126
136
  trip_id: trip[:trip2_id],
127
137
  origin_id: trip[:trip2_origin_id],
128
138
  destination_id: trip[:trip2_destination_id],
129
- departure_time: trip[:trip2_departure_time],
139
+ departure_time: parse_time(trip[:trip2_departure_time]),
130
140
  duration: trip[:trip2_duration],
131
141
  vendor_name: trip[:trip2_vendor_name],
132
142
  route_name: trip[:route2_name],
@@ -0,0 +1,12 @@
1
+ class RemoveUniqueSlugIndexOnSpreeCmsPages < ActiveRecord::Migration[7.0]
2
+ def change
3
+ if index_exists?(:spree_cms_pages,
4
+ [:slug, :store_id, :deleted_at],
5
+ unique: true,
6
+ name: "index_spree_cms_pages_on_slug_and_store_id_and_deleted_at")
7
+
8
+ remove_index :spree_cms_pages,
9
+ name: "index_spree_cms_pages_on_slug_and_store_id_and_deleted_at"
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ class AddUniqueIndexOnSlugTenantIdDeletedAtToSpreeCmsPages < ActiveRecord::Migration[7.0]
2
+ def change
3
+ unless index_exists?(:spree_cms_pages,
4
+ [:slug, :tenant_id, :deleted_at],
5
+ unique: true,
6
+ name: "index_spree_cms_pages_on_slug_and_tenant_id_and_deleted_at")
7
+
8
+ add_index :spree_cms_pages, [:slug, :tenant_id, :deleted_at],
9
+ unique: true,
10
+ name: "index_spree_cms_pages_on_slug_and_tenant_id_and_deleted_at"
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ FactoryBot.define do
2
+ factory :cm_cms_page, class: 'Spree::CmsPage' do
3
+ sequence(:slug) { |n| "page-slug-#{n}" }
4
+ title { "Sample Page Title" }
5
+ association :store, factory: :store
6
+ locale { 'en' }
7
+ type { 'Spree::Cms::Pages::StandardPage' }
8
+ tenant { nil }
9
+ deleted_at { nil }
10
+ end
11
+ end
@@ -1,5 +1,5 @@
1
1
  module SpreeCmCommissioner
2
- VERSION = '1.13.0'.freeze
2
+ VERSION = '1.14.0'.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: 1.13.0
4
+ version: 1.14.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - You
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-05-27 00:00:00.000000000 Z
11
+ date: 2025-05-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: spree
@@ -961,12 +961,14 @@ files:
961
961
  - app/errors/spree_cm_commissioner/unauthorized_event_error.rb
962
962
  - app/errors/spree_cm_commissioner/unauthorized_vendor_error.rb
963
963
  - app/exception_notifier/spree_cm_commissioner/telegram_notifier.rb
964
+ - app/factory/spree_cm_commissioner/invite_guest_claimed_telegram_message_factory.rb
964
965
  - app/factory/spree_cm_commissioner/order_telegram_message_factory.rb
965
966
  - app/factory/spree_cm_commissioner/telegram_message_factory.rb
966
967
  - app/finders/spree_cm_commissioner/line_items/find_by_variant_decorator.rb
967
968
  - app/finders/spree_cm_commissioner/orders/find.rb
968
969
  - app/finders/spree_cm_commissioner/orders/find_by_state.rb
969
970
  - app/finders/spree_cm_commissioner/payment_methods/group_by_bank.rb
971
+ - app/finders/spree_cm_commissioner/products/find_decorator.rb
970
972
  - app/helpers/spree/admin/base_helper_decorator.rb
971
973
  - app/helpers/spree/admin/google_wallets_helper.rb
972
974
  - app/helpers/spree/base_helper_decorator.rb
@@ -985,6 +987,7 @@ files:
985
987
  - app/helpers/spree_cm_commissioner/pin_code_sender_helper.rb
986
988
  - app/helpers/spree_cm_commissioner/telegram/base_helper.rb
987
989
  - app/helpers/spree_cm_commissioner/transit/service_calendars_helper.rb
990
+ - app/helpers/spree_cm_commissioner/transit/trip_helper.rb
988
991
  - app/interactors/spree_cm_commissioner/accommodation_search_detail.rb
989
992
  - app/interactors/spree_cm_commissioner/account_deletion.rb
990
993
  - app/interactors/spree_cm_commissioner/account_deletion_cron_executor.rb
@@ -2423,6 +2426,8 @@ files:
2423
2426
  - db/migrate/20250520044533_add_event_to_spree_line_items.rb
2424
2427
  - db/migrate/20250521024345_add_tenant_id_to_cm_waiting_room_sessions.rb
2425
2428
  - db/migrate/20250521095539_add_kyc_to_spree_variants.rb
2429
+ - db/migrate/20250528073748_remove_unique_slug_index_on_spree_cms_pages.rb
2430
+ - db/migrate/20250528074043_add_unique_index_on_slug_tenant_id_deleted_at_to_spree_cms_pages.rb
2426
2431
  - docker-compose.yml
2427
2432
  - docs/option_types/attr_types.md
2428
2433
  - docs/private_key.pem
@@ -2456,6 +2461,7 @@ files:
2456
2461
  - lib/spree_cm_commissioner/test_helper/factories/back_image_factory.rb
2457
2462
  - lib/spree_cm_commissioner/test_helper/factories/branch_factory.rb
2458
2463
  - lib/spree_cm_commissioner/test_helper/factories/check_in_factory.rb
2464
+ - lib/spree_cm_commissioner/test_helper/factories/cms_page_factory.rb
2459
2465
  - lib/spree_cm_commissioner/test_helper/factories/country_factory.rb
2460
2466
  - lib/spree_cm_commissioner/test_helper/factories/customer_factory.rb
2461
2467
  - lib/spree_cm_commissioner/test_helper/factories/customer_notification_factory.rb