spree_cm_commissioner 2.4.2 → 2.5.0.pre.pre1
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 +4 -4
- data/.github/workflows/test_and_build_gem.yml +1 -1
- data/.tool-versions +1 -1
- data/Gemfile.lock +1 -1
- data/README.md +32 -0
- data/app/controllers/spree/admin/integration_mappings_controller.rb +21 -0
- data/app/controllers/spree/admin/integration_sessions_controller.rb +21 -0
- data/app/controllers/spree/admin/integrations_controller.rb +83 -0
- data/app/controllers/spree/api/v2/storefront/event_matches_controller.rb +15 -0
- data/app/controllers/spree/api/v2/storefront/tenants_controller.rb +30 -0
- data/app/errors/spree_cm_commissioner/integrations/external_client_error.rb +10 -0
- data/app/errors/spree_cm_commissioner/integrations/sync_error.rb +4 -0
- data/app/finders/spree_cm_commissioner/events/find_matches.rb +15 -0
- data/app/helpers/spree_cm_commissioner/external_integrations_helper.rb +58 -0
- data/app/interactors/spree_cm_commissioner/stock/inventory_item_resetter.rb +1 -1
- data/app/interactors/spree_cm_commissioner/stock/stock_movement_creator.rb +4 -2
- data/app/jobs/spree_cm_commissioner/integrations/base_job.rb +39 -0
- data/app/jobs/spree_cm_commissioner/integrations/polling_job.rb +53 -0
- data/app/jobs/spree_cm_commissioner/integrations/polling_scheduler_job.rb +30 -0
- data/app/jobs/spree_cm_commissioner/stock/inventory_items_adjuster_job.rb +5 -4
- data/app/jobs/spree_cm_commissioner/telegram_alerts/integration_sync_failure_job.rb +17 -0
- data/app/models/concerns/spree_cm_commissioner/integrations/integration_mappable.rb +58 -0
- data/app/models/concerns/spree_cm_commissioner/option_type_attr_type.rb +15 -3
- data/app/models/concerns/spree_cm_commissioner/store_metadata.rb +14 -2
- data/app/models/concerns/spree_cm_commissioner/tenant_preference.rb +2 -0
- data/app/models/concerns/spree_cm_commissioner/variant_options_concern.rb +1 -7
- data/app/models/spree_cm_commissioner/integration.rb +21 -0
- data/app/models/spree_cm_commissioner/integration_mapping.rb +37 -0
- data/app/models/spree_cm_commissioner/integration_sync_session.rb +15 -0
- data/app/models/spree_cm_commissioner/integrations/stadium_x_v1.rb +21 -0
- data/app/models/spree_cm_commissioner/inventory_item.rb +5 -1
- data/app/models/spree_cm_commissioner/option_type_decorator.rb +8 -0
- data/app/models/spree_cm_commissioner/option_value_decorator.rb +34 -0
- data/app/models/spree_cm_commissioner/product_decorator.rb +3 -2
- data/app/models/spree_cm_commissioner/redis_stock/cached_inventory_items_builder.rb +2 -2
- data/app/models/spree_cm_commissioner/redis_stock/inventory_updater.rb +2 -2
- data/app/models/spree_cm_commissioner/taxon_decorator.rb +1 -0
- data/app/models/spree_cm_commissioner/taxonomy_decorator.rb +13 -1
- data/app/models/spree_cm_commissioner/variant_decorator.rb +7 -4
- data/app/models/spree_cm_commissioner/vendor_decorator.rb +1 -0
- data/app/overrides/spree/admin/shared/sub_menu/_integrations/external_integrations.html.erb.deface +6 -0
- data/app/presenters/spree/variants/{visable_options_presenter.rb → visible_options_presenter.rb} +2 -4
- data/app/serializers/spree/v2/storefront/tenant_serializer.rb +14 -0
- data/app/services/spree_cm_commissioner/integrations/base/sync_manager.rb +69 -0
- data/app/services/spree_cm_commissioner/integrations/base/sync_result.rb +183 -0
- data/app/services/spree_cm_commissioner/integrations/polling.rb +70 -0
- data/app/services/spree_cm_commissioner/integrations/polling_scheduler.rb +79 -0
- data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/external_client/client.rb +152 -0
- data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/polling/sync_matches.rb +113 -0
- data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/polling/sync_zones.rb +215 -0
- data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/resources/base.rb +20 -0
- data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/resources/league.rb +19 -0
- data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/resources/match.rb +95 -0
- data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/resources/ticket.rb +81 -0
- data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/resources/ticket_image.rb +19 -0
- data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/resources/zone.rb +90 -0
- data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/sync_manager.rb +35 -0
- data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/sync_strategies/full_sync_strategy.rb +38 -0
- data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/sync_strategies/incremental_sync_strategy.rb +44 -0
- data/app/services/spree_cm_commissioner/integrations/stadium_x_v1/sync_strategies/webhook_sync_strategy.rb +16 -0
- data/app/services/spree_cm_commissioner/telegram_alerts/integration_sync_failure.rb +49 -0
- data/app/views/spree/admin/integration_mappings/_integration_mappings.html.erb +107 -0
- data/app/views/spree/admin/integration_mappings/index.html.erb +33 -0
- data/app/views/spree/admin/integration_sessions/_integration_sync_sessions.html.erb +116 -0
- data/app/views/spree/admin/integration_sessions/index.html.erb +42 -0
- data/app/views/spree/admin/integrations/_form.html.erb +104 -0
- data/app/views/spree/admin/integrations/_stadium_x_v1_fields.html.erb +29 -0
- data/app/views/spree/admin/integrations/edit.html.erb +45 -0
- data/app/views/spree/admin/integrations/index.html.erb +75 -0
- data/app/views/spree/admin/integrations/new.html.erb +25 -0
- data/app/views/spree/admin/tenants/_form.html.erb +79 -36
- data/config/locales/en.yml +8 -0
- data/config/locales/km.yml +8 -0
- data/config/routes.rb +9 -1
- data/db/migrate/20251017094845_create_cm_integrations.rb +22 -0
- data/db/migrate/20251017101555_create_cm_integration_sync_sessions.rb +68 -0
- data/db/migrate/20251017101605_create_cm_integration_mappings.rb +52 -0
- data/lib/cm_app_logger.rb +1 -0
- data/lib/spree_cm_commissioner/test_helper/factories/integration_factory.rb +25 -0
- data/lib/spree_cm_commissioner/test_helper/factories/integration_mapping_factory.rb +14 -0
- data/lib/spree_cm_commissioner/test_helper/factories/integration_sync_session_factory.rb +7 -0
- data/lib/spree_cm_commissioner/version.rb +1 -1
- data/lib/spree_cm_commissioner.rb +8 -7
- metadata +58 -5
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
module SpreeCmCommissioner
|
|
2
|
+
module TelegramAlerts
|
|
3
|
+
class IntegrationSyncFailure
|
|
4
|
+
prepend ::Spree::ServiceModule::Base
|
|
5
|
+
|
|
6
|
+
# Send Telegram alert for integration sync failure
|
|
7
|
+
# @param error_message [String] The error message
|
|
8
|
+
# @param data [Hash] Additional context data (e.g., sync_type, match_id, event_type)
|
|
9
|
+
def call(error_message:, data: {})
|
|
10
|
+
chat_id = ENV.fetch('EXCEPTION_NOTIFIER_TELEGRAM_CHANNEL_ID', nil)
|
|
11
|
+
return failure(nil, 'Telegram chat ID not configured') if chat_id.blank?
|
|
12
|
+
|
|
13
|
+
telegram_client = ::Telegram.bots[:exception_notifier]
|
|
14
|
+
return failure(nil, 'Telegram bot not configured') if telegram_client.blank?
|
|
15
|
+
|
|
16
|
+
telegram_client.send_message(
|
|
17
|
+
chat_id: chat_id,
|
|
18
|
+
parse_mode: 'HTML',
|
|
19
|
+
text: format_message(error_message, data)
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
success(message: 'Alert sent successfully')
|
|
23
|
+
rescue StandardError => e
|
|
24
|
+
failure(nil, "Failed to send Telegram alert: #{e.message}")
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def format_message(error_message, data)
|
|
30
|
+
text = []
|
|
31
|
+
|
|
32
|
+
text << '🚨 <b>Integration Sync Failed</b>'
|
|
33
|
+
|
|
34
|
+
# Render all data fields dynamically
|
|
35
|
+
data.each do |key, value|
|
|
36
|
+
next if value.blank?
|
|
37
|
+
|
|
38
|
+
formatted_key = key.to_s.humanize
|
|
39
|
+
text << "<b>#{formatted_key}:</b> <code>#{value}</code>"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
text << "<b>Error:</b> <code>#{error_message}</code>"
|
|
43
|
+
text << "<b>Time:</b> <code>#{Time.current.iso8601}</code>"
|
|
44
|
+
|
|
45
|
+
text.compact.join("\n")
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
<div class="table-responsive">
|
|
2
|
+
<table class="table table-sm" id="listing_integration_mappings" data-hook>
|
|
3
|
+
<thead class="text-muted">
|
|
4
|
+
<tr>
|
|
5
|
+
<th><%= Spree.t(:id) %></th>
|
|
6
|
+
<th><%= Spree.t(:external_id) %></th>
|
|
7
|
+
<th><%= Spree.t(:internal_type) %></th>
|
|
8
|
+
<th><%= Spree.t(:internal_id) %></th>
|
|
9
|
+
<th><%= Spree.t(:status) %></th>
|
|
10
|
+
<th><%= Spree.t(:last_synced_at) %></th>
|
|
11
|
+
<th><%= Spree.t(:created_at) %></th>
|
|
12
|
+
<th><%= Spree.t(:updated_at) %></th>
|
|
13
|
+
<th></th>
|
|
14
|
+
</tr>
|
|
15
|
+
</thead>
|
|
16
|
+
|
|
17
|
+
<tbody>
|
|
18
|
+
<% mappings = defined?(@mappings) ? @mappings : integration.integration_mappings.order(updated_at: :desc).limit(25) %>
|
|
19
|
+
<% mappings.each do |mapping| %>
|
|
20
|
+
<tr id="integration_mapping_<%= mapping.id %>">
|
|
21
|
+
<td><%= mapping.id %></td>
|
|
22
|
+
<td><%= mapping.external_id %></td>
|
|
23
|
+
<td><%= mapping.internal_type %></td>
|
|
24
|
+
<td>
|
|
25
|
+
<%= integration_mapping_internal_link(mapping) %>
|
|
26
|
+
</td>
|
|
27
|
+
<td><%= mapping.status %></td>
|
|
28
|
+
<td><%= mapping.last_synced_at %></td>
|
|
29
|
+
<td><%= mapping.created_at %></td>
|
|
30
|
+
<td><%= mapping.updated_at %></td>
|
|
31
|
+
|
|
32
|
+
<td class="actions">
|
|
33
|
+
<% if mapping.external_payload.present? %>
|
|
34
|
+
<%= link_to_with_icon 'activity.svg', Spree.t("admin.external_integrations.view_result"), "#mapping_payload_modal_#{mapping.id}",
|
|
35
|
+
class: 'btn btn-light btn-sm',
|
|
36
|
+
no_text: true,
|
|
37
|
+
data: { toggle: 'modal', target: "#mapping_payload_modal_#{mapping.id}" },
|
|
38
|
+
title: Spree.t("admin.external_integrations.external_payload") %>
|
|
39
|
+
<% end %>
|
|
40
|
+
</td>
|
|
41
|
+
</tr>
|
|
42
|
+
<% end %>
|
|
43
|
+
</tbody>
|
|
44
|
+
</table>
|
|
45
|
+
|
|
46
|
+
<% if mappings.empty? %>
|
|
47
|
+
<small class="form-text text-muted"><%= Spree.t("admin.external_integrations.no_results") %></small>
|
|
48
|
+
<% end %>
|
|
49
|
+
|
|
50
|
+
<% if defined?(@mappings) && @mappings.respond_to?(:total_pages) %>
|
|
51
|
+
<div class="mt-3">
|
|
52
|
+
<%= paginate @mappings, theme: 'admin-twitter-bootstrap-4' %>
|
|
53
|
+
</div>
|
|
54
|
+
<% end %>
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
<% mappings.each do |mapping| %>
|
|
58
|
+
<% if mapping.external_payload.present? %>
|
|
59
|
+
<div
|
|
60
|
+
class="modal fade"
|
|
61
|
+
id="mapping_payload_modal_<%= mapping.id %>"
|
|
62
|
+
tabindex="-1"
|
|
63
|
+
role="dialog"
|
|
64
|
+
aria-labelledby="mapping_payload_modal_label_<%= mapping.id %>"
|
|
65
|
+
aria-hidden="true"
|
|
66
|
+
>
|
|
67
|
+
<div class="modal-dialog modal-lg" role="document">
|
|
68
|
+
<div class="modal-content">
|
|
69
|
+
<div class="modal-header">
|
|
70
|
+
<h5
|
|
71
|
+
class="modal-title"
|
|
72
|
+
id="mapping_payload_modal_label_<%= mapping.id %>"
|
|
73
|
+
>
|
|
74
|
+
<%= Spree.t("admin.external_integrations.external_payload") %> - Mapping #<%= mapping.id %>
|
|
75
|
+
</h5>
|
|
76
|
+
|
|
77
|
+
<button
|
|
78
|
+
type="button"
|
|
79
|
+
class="close"
|
|
80
|
+
data-dismiss="modal"
|
|
81
|
+
aria-label="Close"
|
|
82
|
+
>
|
|
83
|
+
<span aria-hidden="true">×</span>
|
|
84
|
+
</button>
|
|
85
|
+
</div>
|
|
86
|
+
|
|
87
|
+
<div class="modal-body">
|
|
88
|
+
<pre
|
|
89
|
+
class="small mb-0 p-2 bg-light border rounded"
|
|
90
|
+
style="max-height: 500px; overflow-y: auto;"
|
|
91
|
+
><code><%= JSON.pretty_generate(mapping.external_payload) %></code></pre>
|
|
92
|
+
</div>
|
|
93
|
+
|
|
94
|
+
<div class="modal-footer">
|
|
95
|
+
<button
|
|
96
|
+
type="button"
|
|
97
|
+
class="btn btn-secondary"
|
|
98
|
+
data-dismiss="modal"
|
|
99
|
+
>
|
|
100
|
+
<%= Spree.t(:close) %>
|
|
101
|
+
</button>
|
|
102
|
+
</div>
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
<% end %>
|
|
107
|
+
<% end %>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<% content_for :page_title do %>
|
|
2
|
+
<%= link_to Spree.t('external_integrations'), spree.admin_integrations_url %> / <%= @integration.name %>
|
|
3
|
+
<% end %>
|
|
4
|
+
|
|
5
|
+
<% content_for :page_tabs do %>
|
|
6
|
+
<li class="nav-item">
|
|
7
|
+
<%= link_to Spree.t(:edit),
|
|
8
|
+
edit_admin_integration_path(@integration),
|
|
9
|
+
class: "nav-link" %>
|
|
10
|
+
</li>
|
|
11
|
+
|
|
12
|
+
<li class="nav-item">
|
|
13
|
+
<%= link_to Spree.t(:integration_sync_sessions),
|
|
14
|
+
admin_integration_sessions_path(@integration),
|
|
15
|
+
class: "nav-link" %>
|
|
16
|
+
</li>
|
|
17
|
+
|
|
18
|
+
<li class="nav-item">
|
|
19
|
+
<%= link_to Spree.t(:integration_mappings),
|
|
20
|
+
admin_integration_mappings_path(@integration),
|
|
21
|
+
class: "nav-link active" %>
|
|
22
|
+
</li>
|
|
23
|
+
<% end %>
|
|
24
|
+
|
|
25
|
+
<div data-hook="admin_integrations_mappings" class="card mb-3">
|
|
26
|
+
<div class="card-header">
|
|
27
|
+
<h5 class="card-title mb-0 h6"><%= Spree.t(:integration_mappings) %></h5>
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
<div class="card-body">
|
|
31
|
+
<%= render partial: 'integration_mappings', locals: { integration: @integration } %>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
<div class="table-responsive">
|
|
2
|
+
<table
|
|
3
|
+
class="table table-sm"
|
|
4
|
+
id="listing_integration_sync_sessions"
|
|
5
|
+
data-hook
|
|
6
|
+
>
|
|
7
|
+
<thead class="text-muted">
|
|
8
|
+
<tr>
|
|
9
|
+
<th><%= Spree.t(:id) %></th>
|
|
10
|
+
<th><%= Spree.t(:sync_type) %></th>
|
|
11
|
+
<th><%= Spree.t(:status) %></th>
|
|
12
|
+
<th><%= Spree.t(:started_at) %></th>
|
|
13
|
+
<th><%= Spree.t(:ended_at) %></th>
|
|
14
|
+
<th><%= Spree.t(:duration) %></th>
|
|
15
|
+
<th></th>
|
|
16
|
+
</tr>
|
|
17
|
+
</thead>
|
|
18
|
+
|
|
19
|
+
<tbody>
|
|
20
|
+
<% sync_sessions = defined?(@sync_sessions) ? @sync_sessions : integration.integration_sync_sessions.order(created_at: :desc).limit(25) %>
|
|
21
|
+
<% sync_sessions.each do |sess| %>
|
|
22
|
+
<tr id="integration_sync_session_<%= sess.id %>">
|
|
23
|
+
<td><%= sess.id %></td>
|
|
24
|
+
<td><%= sess.sync_type %></td>
|
|
25
|
+
<td><%= sess.status %></td>
|
|
26
|
+
<td><%= sess.started_at %></td>
|
|
27
|
+
<td><%= sess.ended_at %></td>
|
|
28
|
+
<td>
|
|
29
|
+
<% if sess.started_at && sess.ended_at %>
|
|
30
|
+
<% duration = (sess.ended_at - sess.started_at).to_i %>
|
|
31
|
+
|
|
32
|
+
<% if duration < 60 %>
|
|
33
|
+
<%= "#{duration} sec" %>
|
|
34
|
+
<% else %>
|
|
35
|
+
<%= "#{duration / 60} min" %>
|
|
36
|
+
<% end %>
|
|
37
|
+
<% else %>
|
|
38
|
+
N/A
|
|
39
|
+
<% end %>
|
|
40
|
+
</td>
|
|
41
|
+
<td class="actions">
|
|
42
|
+
<% if sess.sync_result.present? %>
|
|
43
|
+
<%= link_to_with_icon 'activity.svg', Spree.t("admin.external_integrations.view_result"), "#session_result_modal_#{sess.id}",
|
|
44
|
+
class: 'btn btn-light btn-sm',
|
|
45
|
+
no_text: true,
|
|
46
|
+
data: { toggle: 'modal', target: "#session_result_modal_#{sess.id}" },
|
|
47
|
+
title: Spree.t("admin.external_integrations.sync_result") %>
|
|
48
|
+
<% end %>
|
|
49
|
+
</td>
|
|
50
|
+
</tr>
|
|
51
|
+
<% end %>
|
|
52
|
+
</tbody>
|
|
53
|
+
</table>
|
|
54
|
+
|
|
55
|
+
<% if sync_sessions.empty? %>
|
|
56
|
+
<small class="form-text text-muted"><%= Spree.t("admin.external_integrations.no_results") %></small>
|
|
57
|
+
<% end %>
|
|
58
|
+
|
|
59
|
+
<% if defined?(@sync_sessions) && @sync_sessions.respond_to?(:total_pages) %>
|
|
60
|
+
<div class="mt-3">
|
|
61
|
+
<%= paginate @sync_sessions, theme: 'admin-twitter-bootstrap-4' %>
|
|
62
|
+
</div>
|
|
63
|
+
<% end %>
|
|
64
|
+
</div>
|
|
65
|
+
|
|
66
|
+
<% sync_sessions.each do |sess| %>
|
|
67
|
+
<% if sess.sync_result.present? %>
|
|
68
|
+
<div
|
|
69
|
+
class="modal fade"
|
|
70
|
+
id="session_result_modal_<%= sess.id %>"
|
|
71
|
+
tabindex="-1"
|
|
72
|
+
role="dialog"
|
|
73
|
+
aria-labelledby="session_result_modal_label_<%= sess.id %>"
|
|
74
|
+
aria-hidden="true"
|
|
75
|
+
>
|
|
76
|
+
<div class="modal-dialog modal-lg" role="document">
|
|
77
|
+
<div class="modal-content">
|
|
78
|
+
<div class="modal-header">
|
|
79
|
+
<h5
|
|
80
|
+
class="modal-title"
|
|
81
|
+
id="session_result_modal_label_<%= sess.id %>"
|
|
82
|
+
>
|
|
83
|
+
<%= Spree.t("admin.external_integrations.sync_result") %> - Session #<%= sess.id %>
|
|
84
|
+
</h5>
|
|
85
|
+
|
|
86
|
+
<button
|
|
87
|
+
type="button"
|
|
88
|
+
class="close"
|
|
89
|
+
data-dismiss="modal"
|
|
90
|
+
aria-label="Close"
|
|
91
|
+
>
|
|
92
|
+
<span aria-hidden="true">×</span>
|
|
93
|
+
</button>
|
|
94
|
+
</div>
|
|
95
|
+
|
|
96
|
+
<div class="modal-body">
|
|
97
|
+
<pre
|
|
98
|
+
class="small mb-0 p-2 bg-light border rounded"
|
|
99
|
+
style="max-height: 500px; overflow-y: auto;"
|
|
100
|
+
><code><%= JSON.pretty_generate(sess.sync_result) %></code></pre>
|
|
101
|
+
</div>
|
|
102
|
+
|
|
103
|
+
<div class="modal-footer">
|
|
104
|
+
<button
|
|
105
|
+
type="button"
|
|
106
|
+
class="btn btn-secondary"
|
|
107
|
+
data-dismiss="modal"
|
|
108
|
+
>
|
|
109
|
+
<%= Spree.t(:close) %>
|
|
110
|
+
</button>
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
115
|
+
<% end %>
|
|
116
|
+
<% end %>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<% content_for :page_title do %>
|
|
2
|
+
<%= link_to Spree.t('external_integrations'), spree.admin_integrations_url %> / <%= @integration.name %>
|
|
3
|
+
<% end %>
|
|
4
|
+
|
|
5
|
+
<% content_for :page_tabs do %>
|
|
6
|
+
<li class="nav-item">
|
|
7
|
+
<%= link_to Spree.t(:edit),
|
|
8
|
+
edit_admin_integration_path(@integration),
|
|
9
|
+
class: "nav-link" %>
|
|
10
|
+
</li>
|
|
11
|
+
|
|
12
|
+
<li class="nav-item">
|
|
13
|
+
<%= link_to Spree.t(:integration_sync_sessions),
|
|
14
|
+
admin_integration_sessions_path(@integration),
|
|
15
|
+
class: "nav-link active" %>
|
|
16
|
+
</li>
|
|
17
|
+
|
|
18
|
+
<li class="nav-item">
|
|
19
|
+
<%= link_to Spree.t(:integration_mappings),
|
|
20
|
+
admin_integration_mappings_path(@integration),
|
|
21
|
+
class: "nav-link" %>
|
|
22
|
+
</li>
|
|
23
|
+
<% end %>
|
|
24
|
+
|
|
25
|
+
<div data-hook="admin_integrations_sessions" class="card mb-3">
|
|
26
|
+
<div class="card-header d-flex justify-content-between align-items-center">
|
|
27
|
+
<h5 class="card-title mb-0 h6">
|
|
28
|
+
<%= Spree.t(:integration_sync_sessions) %>
|
|
29
|
+
</h5>
|
|
30
|
+
|
|
31
|
+
<div class="card-header-actions">
|
|
32
|
+
<%= button_to Spree.t(:enqueue_full_sync),
|
|
33
|
+
enqueue_polling_admin_integration_path(@integration, sync_type: :full),
|
|
34
|
+
method: :post,
|
|
35
|
+
class: 'btn btn-primary btn-sm' %>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
<div class="card-body">
|
|
40
|
+
<%= render partial: 'integration_sync_sessions', locals: { integration: @integration } %>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
<div data-hook="admin_external_integrations_form_fields" class="row">
|
|
2
|
+
<div class="col-6">
|
|
3
|
+
<%= f.field_container :type do %>
|
|
4
|
+
<%= f.label :type, raw(I18n.t('spree.admin.external_integrations.integration_type', default: 'Integration type') + required_span_tag) %>
|
|
5
|
+
|
|
6
|
+
<% if f.object.persisted? %>
|
|
7
|
+
<%= f.text_field :type, value: f.object.type, class: 'form-control', disabled: true, readonly: true %>
|
|
8
|
+
<%= f.hidden_field :type, value: f.object.type %>
|
|
9
|
+
<% else %>
|
|
10
|
+
<%= f.select :type,
|
|
11
|
+
options_for_select(@integration_type_options, f.object.type),
|
|
12
|
+
{ include_blank: Spree.t(:choose_an_option) },
|
|
13
|
+
class: 'form-control select2',
|
|
14
|
+
required: true %>
|
|
15
|
+
<% end %>
|
|
16
|
+
|
|
17
|
+
<%= f.error_message_on :type %>
|
|
18
|
+
<% end %>
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
<div class="col-6">
|
|
22
|
+
<%= f.field_container :name do %>
|
|
23
|
+
<%= f.label :name, raw(Spree.t(:name) + required_span_tag) %>
|
|
24
|
+
<%= f.text_field :name, required: true, class: 'form-control', placeholder: Spree.t(:name) %>
|
|
25
|
+
<%= f.error_message_on :name %>
|
|
26
|
+
<% end %>
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
<div class="col-6">
|
|
30
|
+
<%= f.field_container :vendor_id do %>
|
|
31
|
+
<%= f.label :vendor_id, raw(I18n.t('spree.admin.external_integrations.vendor', default: 'Vendor') + required_span_tag) %>
|
|
32
|
+
|
|
33
|
+
<%= f.select :vendor_id,
|
|
34
|
+
options_from_collection_for_select(@vendors, :id, :name, f.object.vendor_id),
|
|
35
|
+
{ include_blank: Spree.t(:choose_an_option) },
|
|
36
|
+
class: 'form-control select2',
|
|
37
|
+
required: true %>
|
|
38
|
+
|
|
39
|
+
<%= f.error_message_on :vendor_id %>
|
|
40
|
+
<% end %>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
<div class="col-6">
|
|
44
|
+
<%= f.field_container :tenant_id do %>
|
|
45
|
+
<%= f.label :tenant_id, I18n.t('spree.admin.external_integrations.tenant', default: 'Tenant') %>
|
|
46
|
+
|
|
47
|
+
<%= f.select :tenant_id,
|
|
48
|
+
options_from_collection_for_select(@tenants, :id, :name, f.object.tenant_id),
|
|
49
|
+
{ include_blank: Spree.t(:choose_an_option), prompt: Spree.t(:optional) },
|
|
50
|
+
class: 'form-control select2',
|
|
51
|
+
data: { allow_clear: true, placeholder: Spree.t(:optional) } %>
|
|
52
|
+
|
|
53
|
+
<%= f.error_message_on :tenant_id %>
|
|
54
|
+
<% end %>
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
<div class="col-6">
|
|
58
|
+
<%= f.field_container :status do %>
|
|
59
|
+
<%= f.label :status, raw(Spree.t(:status) + required_span_tag) %>
|
|
60
|
+
|
|
61
|
+
<%= f.select :status,
|
|
62
|
+
options_for_select(@status_options, f.object.status),
|
|
63
|
+
{},
|
|
64
|
+
class: 'form-control select2',
|
|
65
|
+
required: true %>
|
|
66
|
+
|
|
67
|
+
<%= f.error_message_on :status %>
|
|
68
|
+
<% end %>
|
|
69
|
+
</div>
|
|
70
|
+
|
|
71
|
+
<div class="col-6">
|
|
72
|
+
<%= f.field_container :conflict_strategy do %>
|
|
73
|
+
<%= f.label :conflict_strategy, raw(I18n.t('spree.admin.external_integrations.conflict_strategy', default: 'Conflict strategy') + required_span_tag) %>
|
|
74
|
+
|
|
75
|
+
<%= f.select :conflict_strategy,
|
|
76
|
+
options_for_select(@conflict_strategy_options, f.object.conflict_strategy),
|
|
77
|
+
{},
|
|
78
|
+
class: 'form-control select2',
|
|
79
|
+
required: true %>
|
|
80
|
+
|
|
81
|
+
<%= f.error_message_on :conflict_strategy %>
|
|
82
|
+
<% end %>
|
|
83
|
+
</div>
|
|
84
|
+
|
|
85
|
+
<div class="col-6">
|
|
86
|
+
<%= f.field_container :incremental_sync_interval_seconds do %>
|
|
87
|
+
<%= f.label :incremental_sync_interval_seconds, raw(I18n.t('spree.admin.external_integrations.incremental_sync_interval_seconds', default: 'Incremental sync interval (seconds)') + required_span_tag) %>
|
|
88
|
+
<%= f.number_field :incremental_sync_interval_seconds, class: 'form-control', min: 1, max: 3600, required: true %>
|
|
89
|
+
<%= f.error_message_on :incremental_sync_interval_seconds %>
|
|
90
|
+
<% end %>
|
|
91
|
+
</div>
|
|
92
|
+
|
|
93
|
+
<div class="col-6">
|
|
94
|
+
<%= f.field_container :full_sync_interval_hours do %>
|
|
95
|
+
<%= f.label :full_sync_interval_hours, raw(I18n.t('spree.admin.external_integrations.full_sync_interval_hours', default: 'Full sync interval (hours)') + required_span_tag) %>
|
|
96
|
+
<%= f.number_field :full_sync_interval_hours, class: 'form-control', min: 1, max: 168, required: true %>
|
|
97
|
+
<%= f.error_message_on :full_sync_interval_hours %>
|
|
98
|
+
<% end %>
|
|
99
|
+
</div>
|
|
100
|
+
|
|
101
|
+
<% if f.object.type == 'SpreeCmCommissioner::Integrations::StadiumXV1' || (f.object.new_record? && params[:type] == 'SpreeCmCommissioner::Integrations::StadiumXV1') %>
|
|
102
|
+
<%= render partial: 'stadium_x_v1_fields', locals: { f: f } %>
|
|
103
|
+
<% end %>
|
|
104
|
+
</div>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<!-- Stadium X V1 API Credentials -->
|
|
2
|
+
<div class="col-12">
|
|
3
|
+
<hr class="my-4">
|
|
4
|
+
|
|
5
|
+
<h6 class="text-muted">
|
|
6
|
+
<%= I18n.t('spree.admin.external_integrations.stadium_x_credentials', default: 'Stadium X API Credentials') %>
|
|
7
|
+
</h6>
|
|
8
|
+
</div>
|
|
9
|
+
|
|
10
|
+
<div class="col-6">
|
|
11
|
+
<%= f.field_container :public_key do %>
|
|
12
|
+
<%= f.label :public_key, raw(I18n.t('spree.admin.external_integrations.public_key', default: 'Public Key') + required_span_tag) %>
|
|
13
|
+
<%= text_field_tag 'spree_cm_commissioner_integration[private_metadata][public_key]', f.object.public_key, class: 'form-control', required: true %>
|
|
14
|
+
<% end %>
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
<div class="col-6">
|
|
18
|
+
<%= f.field_container :private_key do %>
|
|
19
|
+
<%= f.label :private_key, raw(I18n.t('spree.admin.external_integrations.private_key', default: 'Private Key') + required_span_tag) %>
|
|
20
|
+
<%= text_field_tag 'spree_cm_commissioner_integration[private_metadata][private_key]', f.object.private_key, class: 'form-control', required: true %>
|
|
21
|
+
<% end %>
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
<div class="col-6">
|
|
25
|
+
<%= f.field_container :base_url do %>
|
|
26
|
+
<%= f.label :base_url, raw(I18n.t('spree.admin.external_integrations.base_url', default: 'Base URL') + required_span_tag) %>
|
|
27
|
+
<%= text_field_tag 'spree_cm_commissioner_integration[private_metadata][base_url]', f.object.base_url, class: 'form-control', placeholder: 'https://api.stadiumx.com', required: true %>
|
|
28
|
+
<% end %>
|
|
29
|
+
</div>
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<% content_for :page_title do %>
|
|
2
|
+
<%= link_to Spree.t('external_integrations'), spree.admin_integrations_url %> / <%= @object.name %>
|
|
3
|
+
<% end %>
|
|
4
|
+
|
|
5
|
+
<% content_for :page_tabs do %>
|
|
6
|
+
<li class="nav-item">
|
|
7
|
+
<%= link_to Spree.t(:edit),
|
|
8
|
+
edit_admin_integration_path(@object),
|
|
9
|
+
class: "nav-link active" %>
|
|
10
|
+
</li>
|
|
11
|
+
|
|
12
|
+
<li class="nav-item">
|
|
13
|
+
<%= link_to Spree.t(:integration_sync_sessions),
|
|
14
|
+
admin_integration_sessions_path(@object),
|
|
15
|
+
class: "nav-link" %>
|
|
16
|
+
</li>
|
|
17
|
+
|
|
18
|
+
<li class="nav-item">
|
|
19
|
+
<%= link_to Spree.t(:integration_mappings),
|
|
20
|
+
admin_integration_mappings_path(@object),
|
|
21
|
+
class: "nav-link" %>
|
|
22
|
+
</li>
|
|
23
|
+
<% end %>
|
|
24
|
+
|
|
25
|
+
<div data-hook="admin_integrations" class="card mb-3">
|
|
26
|
+
<div class="card-header">
|
|
27
|
+
<h5 class="card-title mb-0 h6"><%= Spree.t('external_integrations') %></h5>
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
<div class="card-body">
|
|
31
|
+
<div data-hook="admin_integrations_edit_form_header">
|
|
32
|
+
<%= render partial: 'spree/admin/shared/error_messages', locals: { target: @object } %>
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
<div data-hook="admin_integrations_edit_form">
|
|
36
|
+
<%= form_with model: @object, url: admin_integration_path(@object), method: :patch, scope: :spree_cm_commissioner_integration do |f| %>
|
|
37
|
+
<%= render partial: 'form', locals: { f: f } %>
|
|
38
|
+
|
|
39
|
+
<div data-hook="admin_integrations_edit_form_buttons">
|
|
40
|
+
<%= render partial: 'spree/admin/shared/edit_resource_links', locals: { collection_url: spree.admin_integrations_path } %>
|
|
41
|
+
</div>
|
|
42
|
+
<% end %>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
<% content_for :page_title do %>
|
|
2
|
+
<%= Spree.t('external_integrations') %>
|
|
3
|
+
<% end %>
|
|
4
|
+
|
|
5
|
+
<% content_for :page_actions do %>
|
|
6
|
+
<%= button_link_to Spree.t(:new_external_integration), new_admin_integration_path, class: "btn-success", icon: 'add.svg' %>
|
|
7
|
+
<% end if can? :create, SpreeCmCommissioner::Integration %>
|
|
8
|
+
|
|
9
|
+
<% if @integrations.any? %>
|
|
10
|
+
<div class="table-responsive border rounded bg-white mb-3">
|
|
11
|
+
<table class="table" id="listing_integrations" data-hook>
|
|
12
|
+
<thead class="text-muted">
|
|
13
|
+
<tr data-hook="admin_integrations_index_headers">
|
|
14
|
+
<th><%= Spree.t(:name) %></th>
|
|
15
|
+
<th><%= Spree.t(:base_url) %></th>
|
|
16
|
+
<th><%= Spree.t(:conflict_strategy) %></th>
|
|
17
|
+
<th><%= Spree.t(:incremental_sync_interval_seconds) %></th>
|
|
18
|
+
<th><%= Spree.t(:full_sync_interval_hours) %></th>
|
|
19
|
+
<th><%= Spree.t(:vendor) %></th>
|
|
20
|
+
<th><%= Spree.t(:status) %></th>
|
|
21
|
+
<th><%= Spree.t(:updated_at) %></th>
|
|
22
|
+
</tr>
|
|
23
|
+
</thead>
|
|
24
|
+
|
|
25
|
+
<tbody>
|
|
26
|
+
<% @integrations.each do |integration| %>
|
|
27
|
+
<tr
|
|
28
|
+
id="<%= spree_dom_id integration %>"
|
|
29
|
+
data-hook="admin_integrations_index_rows"
|
|
30
|
+
>
|
|
31
|
+
<td><%= integration.name %></td>
|
|
32
|
+
|
|
33
|
+
<td>
|
|
34
|
+
<%= integration_base_url_link(integration.base_url) %>
|
|
35
|
+
</td>
|
|
36
|
+
|
|
37
|
+
<td>
|
|
38
|
+
<%= integration_conflict_strategy_badge(integration.conflict_strategy) %>
|
|
39
|
+
</td>
|
|
40
|
+
|
|
41
|
+
<td>
|
|
42
|
+
<%= integration_interval_badge(integration.incremental_sync_interval_seconds, 's') %>
|
|
43
|
+
</td>
|
|
44
|
+
|
|
45
|
+
<td>
|
|
46
|
+
<%= integration_interval_badge(integration.full_sync_interval_hours, 'h') %>
|
|
47
|
+
</td>
|
|
48
|
+
|
|
49
|
+
<td><%= integration.vendor.name %></td>
|
|
50
|
+
|
|
51
|
+
<td>
|
|
52
|
+
<%= integration_status_badge(integration.status) %>
|
|
53
|
+
</td>
|
|
54
|
+
|
|
55
|
+
<td><%= integration.updated_at %></td>
|
|
56
|
+
|
|
57
|
+
<td
|
|
58
|
+
data-hook="admin_integrations_index_row_actions"
|
|
59
|
+
class="actions"
|
|
60
|
+
>
|
|
61
|
+
<span class="d-flex justify-content-end">
|
|
62
|
+
<%= link_to_edit integration, url: edit_admin_integration_path(integration), no_text: true if can?(:edit, integration) %>
|
|
63
|
+
<%= link_to_delete integration, url: admin_integration_path(integration), no_text: true if can?(:delete, integration) %>
|
|
64
|
+
</span>
|
|
65
|
+
</td>
|
|
66
|
+
</tr>
|
|
67
|
+
<% end %>
|
|
68
|
+
</tbody>
|
|
69
|
+
</table>
|
|
70
|
+
</div>
|
|
71
|
+
<% else %>
|
|
72
|
+
<small class="form-text text-muted">
|
|
73
|
+
<%= raw I18n.t('external_integrations.empty_info') %>
|
|
74
|
+
</small>
|
|
75
|
+
<% end %>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<% content_for :page_title do %>
|
|
2
|
+
<%= link_to Spree.t('external_integrations'), spree.admin_integrations_url %> / <%= Spree.t(:new) %>
|
|
3
|
+
<% end %>
|
|
4
|
+
|
|
5
|
+
<div data-hook="admin_integrations" class="card mb-3">
|
|
6
|
+
<div class="card-header">
|
|
7
|
+
<h5 class="card-title mb-0 h6"><%= Spree.t('external_integrations') %></h5>
|
|
8
|
+
</div>
|
|
9
|
+
|
|
10
|
+
<div class="card-body">
|
|
11
|
+
<div data-hook="admin_integrations_new_form_header">
|
|
12
|
+
<%= render partial: 'spree/admin/shared/error_messages', locals: { target: @object } %>
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
<div data-hook="admin_integrations_new_form">
|
|
16
|
+
<%= form_with model: @object, url: { action: 'create' }, scope: :spree_cm_commissioner_integration do |f| %>
|
|
17
|
+
<%= render partial: 'form', locals: { f: f } %>
|
|
18
|
+
|
|
19
|
+
<div data-hook="admin_integrations_new_form_buttons">
|
|
20
|
+
<%= render partial: 'spree/admin/shared/new_resource_links' %>
|
|
21
|
+
</div>
|
|
22
|
+
<% end %>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|