diff --git a/app/models/notification_type.rb b/app/models/notification_type.rb index ed14b37be..f20314c5f 100644 --- a/app/models/notification_type.rb +++ b/app/models/notification_type.rb @@ -72,6 +72,7 @@ class NotificationType notify_user_order_is_ready notify_user_order_is_canceled notify_user_order_is_refunded + notify_admin_low_stock_threshold ] # deprecated: # - notify_member_subscribed_plan_is_changed diff --git a/app/services/product_service.rb b/app/services/product_service.rb index a9ff0dba4..7e9c6c0a5 100644 --- a/app/services/product_service.rb +++ b/app/services/product_service.rb @@ -49,6 +49,13 @@ class ProductService } end || {} product.stock = remaining_stock + affected_stocks = stock_movements&.map { |m| m[:stock_type] }&.uniq + if (remaining_stock[:internal] < product.low_stock_threshold && affected_stocks&.include?('internal')) || + (remaining_stock[:external] < product.low_stock_threshold && affected_stocks&.include?('external')) + NotificationCenter.call type: 'notify_admin_low_stock_threshold', + receiver: User.admins_and_managers, + attached_object: product + end product end diff --git a/app/views/api/notifications/_notify_admin_low_stock_threshold.json.jbuilder b/app/views/api/notifications/_notify_admin_low_stock_threshold.json.jbuilder new file mode 100644 index 000000000..71e3fa7ff --- /dev/null +++ b/app/views/api/notifications/_notify_admin_low_stock_threshold.json.jbuilder @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +json.title notification.notification_type +json.description t('.low_stock', PRODUCT: t(".#{notification.attached_object.name}")) + + link_to(t('.view_product'), "#!/admin/store/products/#{notification.attached_object.id}/edit") diff --git a/app/views/notifications_mailer/notify_admin_low_stock_threshold.html.erb b/app/views/notifications_mailer/notify_admin_low_stock_threshold.html.erb new file mode 100644 index 000000000..0c1bae992 --- /dev/null +++ b/app/views/notifications_mailer/notify_admin_low_stock_threshold.html.erb @@ -0,0 +1,11 @@ +<%= render 'notifications_mailer/shared/hello', recipient: @recipient %> + +
+ <%= t('.body.low_stock', { PRODUCT: @attached_object.name }) %> +
++ <%= t('.body.stocks_state_html', { INTERNAL: @attached_object.stock['internal'], EXTERNAL: @attached_object.stock['external'] }) %> +
++ <%=link_to( t('.body.manage_stock'), "#{root_url}#!/admin/store/products/#{@attached_object.id}/edit", target: "_blank" )%> +
diff --git a/config/locales/en.yml b/config/locales/en.yml index 5871674c1..2ad1f5e96 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -365,6 +365,9 @@ en: import_over: "%{CATEGORY} import is over. " members: "Members" view_results: "View results." + notify_admin_low_stock_threshold: + low_stock: "Low stock for %{PRODUCT}. " + view_product: "View the product." notify_member_about_coupon: enjoy_a_discount_of_PERCENT_with_code_CODE: "Enjoy a discount of %{PERCENT}% with code %{CODE}" enjoy_a_discount_of_AMOUNT_with_code_CODE: "Enjoy a discount of %{AMOUNT} with code %{CODE}" diff --git a/config/locales/mails.en.yml b/config/locales/mails.en.yml index 76421ef15..251cf0c60 100644 --- a/config/locales/mails.en.yml +++ b/config/locales/mails.en.yml @@ -246,6 +246,12 @@ en: you_made_an_import: "You have initiated an import %{CATEGORY}" category_members: "of the members" click_to_view_results: "Click here to view results" + notify_admin_low_stock_threshold: + subject: "Low stock alert" + body: + low_stock: "A new stock movement of %{PRODUCT} has exceeded the low stock threshold." + stocks_state_html: "Current stock status: