dscf-marketplace 0.8.4 → 0.8.6
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/app/controllers/dscf/marketplace/agents_controller.rb +75 -5
- data/app/controllers/dscf/marketplace/aggregator_listings_controller.rb +2 -2
- data/app/controllers/dscf/marketplace/delivery_stops_controller.rb +9 -9
- data/app/controllers/dscf/marketplace/listing_approvals_controller.rb +57 -0
- data/app/controllers/dscf/marketplace/listings_controller.rb +2 -2
- data/app/controllers/dscf/marketplace/orders_controller.rb +1 -1
- data/app/controllers/dscf/marketplace/product_inclusion_requests_controller.rb +127 -0
- data/app/controllers/dscf/marketplace/retailers_controller.rb +61 -0
- data/app/controllers/dscf/marketplace/sub_suppliers_controller.rb +16 -0
- data/app/controllers/dscf/marketplace/supplier_products_controller.rb +27 -2
- data/app/controllers/dscf/marketplace/suppliers_controller.rb +140 -2
- data/app/models/dscf/marketplace/agent.rb +11 -3
- data/app/models/dscf/marketplace/aggregator_listing.rb +4 -4
- data/app/models/dscf/marketplace/category.rb +2 -1
- data/app/models/dscf/marketplace/delivery_order.rb +6 -6
- data/app/models/dscf/marketplace/delivery_stop.rb +4 -4
- data/app/models/dscf/marketplace/listing.rb +9 -8
- data/app/models/dscf/marketplace/listing_approval.rb +30 -0
- data/app/models/dscf/marketplace/order_invoice.rb +5 -5
- data/app/models/dscf/marketplace/product_inclusion_request.rb +62 -0
- data/app/models/dscf/marketplace/retailer.rb +23 -0
- data/app/models/dscf/marketplace/sub_supplier.rb +43 -0
- data/app/models/dscf/marketplace/sub_supplier_product.rb +22 -0
- data/app/models/dscf/marketplace/supplier.rb +53 -1
- data/app/models/dscf/marketplace/supplier_product.rb +1 -1
- data/app/policies/dscf/marketplace/agent_policy.rb +8 -0
- data/app/policies/dscf/marketplace/listing_approval_policy.rb +9 -0
- data/app/policies/dscf/marketplace/product_inclusion_request_policy.rb +17 -0
- data/app/policies/dscf/marketplace/supplier_policy.rb +12 -0
- data/app/serializers/dscf/marketplace/agent_serializer.rb +9 -3
- data/app/serializers/dscf/marketplace/category_serializer.rb +1 -1
- data/app/serializers/dscf/marketplace/listing_approval_serializer.rb +11 -0
- data/app/serializers/dscf/marketplace/listing_serializer.rb +1 -0
- data/app/serializers/dscf/marketplace/product_inclusion_request_serializer.rb +38 -0
- data/app/serializers/dscf/marketplace/retailer_serializer.rb +10 -0
- data/app/serializers/dscf/marketplace/sub_supplier_serializer.rb +15 -0
- data/app/serializers/dscf/marketplace/supplier_product_serializer.rb +2 -1
- data/app/serializers/dscf/marketplace/supplier_serializer.rb +9 -1
- data/app/services/dscf/marketplace/dispute_service.rb +4 -4
- data/app/services/dscf/marketplace/invoice_pdf_generator.rb +1 -1
- data/config/routes.rb +36 -0
- data/db/demo_seeds.rb +120 -0
- data/db/migrate/20251130143731_create_dscf_marketplace_delivery_stops.rb +2 -2
- data/db/migrate/20251130144500_add_delivery_stop_to_delivery_order_items.rb +1 -1
- data/db/migrate/20260514000001_create_dscf_marketplace_suppliers.rb +2 -2
- data/db/migrate/20260514000002_add_supplier_id_to_supplier_products.rb +2 -2
- data/db/migrate/20260514000003_create_dscf_marketplace_order_invoices.rb +2 -2
- data/db/migrate/20260514000005_create_dscf_marketplace_aggregator_listings.rb +5 -5
- data/db/migrate/20260514000006_add_supplier_id_to_addresses.rb +2 -2
- data/db/migrate/20260527000001_add_orchestrator_fields_to_listings.rb +2 -2
- data/db/migrate/20260529000001_create_dscf_marketplace_agents.rb +1 -1
- data/db/migrate/20260616000002_create_dscf_marketplace_retailers.rb +17 -0
- data/db/migrate/20260616000003_create_dscf_marketplace_sub_suppliers.rb +20 -0
- data/db/migrate/20260616000004_create_dscf_marketplace_listing_approvals.rb +29 -0
- data/db/migrate/20260616000005_create_dscf_marketplace_product_inclusion_requests.rb +23 -0
- data/db/migrate/20260616000006_create_dscf_marketplace_sub_supplier_products.rb +32 -0
- data/db/migrate/20260616000007_add_approval_fields_to_dscf_marketplace_supplier_products.rb +7 -0
- data/db/migrate/20260616000008_add_rejection_and_location_to_dscf_marketplace_agents.rb +9 -0
- data/db/migrate/20260616000009_make_agent_id_nullable_in_dscf_marketplace_retailers.rb +9 -0
- data/db/migrate/20260616000010_add_code_to_dscf_marketplace_categories_and_gender_to_dscf_marketplace_agents.rb +24 -0
- data/lib/dscf/marketplace/version.rb +1 -1
- data/spec/factories/dscf/marketplace/categories.rb +1 -0
- data/spec/factories/dscf/marketplace/listing_approvals.rb +8 -0
- data/spec/factories/dscf/marketplace/product_inclusion_requests.rb +9 -0
- data/spec/factories/dscf/marketplace/retailers.rb +9 -0
- data/spec/factories/dscf/marketplace/sub_supplier_products.rb +10 -0
- data/spec/factories/dscf/marketplace/sub_suppliers.rb +11 -0
- metadata +34 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 36275865e4363db165333b5274f3e16ef5ae38cd0c3b4fc3e4fe88f6a32f2d73
|
|
4
|
+
data.tar.gz: e440535b9bd3e6fdb5df853f47af02c43344dc05f8cca68f76d40235995bea25
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 42cc494a65237a972384e89a19603183e7bd8521258d12c317cafdd134b0d965532c0b3d5a91393557573a618b5368b613b29c002743ddda0fcf56fb75051dc4
|
|
7
|
+
data.tar.gz: fd1469a19042fa3ffe9e0ad5b6c0e94077dc791052f79fb3cfa978f46bb67532ac4b8d6c650d23c86c1bb8b53f60dd4be0a5e95655bdce68e3f679d69ab64848
|
|
@@ -9,6 +9,7 @@ module Dscf
|
|
|
9
9
|
obj = @clazz.new(registration_params)
|
|
10
10
|
ActiveRecord::Base.transaction do
|
|
11
11
|
if obj.save
|
|
12
|
+
create_registration_notification(obj)
|
|
12
13
|
render_success("agent.success.register", data: obj, status: :created)
|
|
13
14
|
else
|
|
14
15
|
render_error("agent.errors.register", errors: obj.errors.full_messages[0], status: :unprocessable_entity)
|
|
@@ -23,29 +24,98 @@ module Dscf
|
|
|
23
24
|
render_success("agent.success.destroy")
|
|
24
25
|
end
|
|
25
26
|
|
|
27
|
+
# Verify (approve) or reject an agent based on presence of reason param
|
|
28
|
+
def verify
|
|
29
|
+
@obj = find_record
|
|
30
|
+
authorize @obj, :verify?
|
|
31
|
+
|
|
32
|
+
if params[:reason].present?
|
|
33
|
+
@obj.update!(
|
|
34
|
+
verification_status: :rejected,
|
|
35
|
+
rejection_reason: params[:reason],
|
|
36
|
+
rejected_at: Time.current
|
|
37
|
+
)
|
|
38
|
+
notification = Dscf::Core::Notification.create!(
|
|
39
|
+
notifiable: @obj,
|
|
40
|
+
recipient: current_user,
|
|
41
|
+
notification_type: :rejection,
|
|
42
|
+
title: "Agent Rejected",
|
|
43
|
+
body: "Agent '#{@obj.name}' (#{@obj.code}) has been rejected. Reason: #{params[:reason]}"
|
|
44
|
+
)
|
|
45
|
+
Dscf::Core::NotificationService.deliver(notification)
|
|
46
|
+
render_success("agent.success.rejected", data: @obj)
|
|
47
|
+
else
|
|
48
|
+
@obj.update!(verification_status: :verified)
|
|
49
|
+
render_success("agent.success.verified", data: @obj)
|
|
50
|
+
end
|
|
51
|
+
rescue StandardError => e
|
|
52
|
+
render_error(errors: e.message, status: :unprocessable_entity)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Modify agent's location fields
|
|
56
|
+
def modify_location
|
|
57
|
+
@obj = find_record
|
|
58
|
+
authorize @obj, :modify_location?
|
|
59
|
+
|
|
60
|
+
@obj.update!(
|
|
61
|
+
service_area: params[:service_area],
|
|
62
|
+
sub_city: params[:sub_city],
|
|
63
|
+
woreda: params[:woreda],
|
|
64
|
+
modified_at: Time.current
|
|
65
|
+
)
|
|
66
|
+
notification = Dscf::Core::Notification.create!(
|
|
67
|
+
notifiable: @obj,
|
|
68
|
+
recipient: current_user,
|
|
69
|
+
notification_type: :modification,
|
|
70
|
+
title: "Agent Location Modified",
|
|
71
|
+
body: "Location for agent '#{@obj.name}' (#{@obj.code}) has been updated."
|
|
72
|
+
)
|
|
73
|
+
Dscf::Core::NotificationService.deliver(notification)
|
|
74
|
+
render_success("agent.success.location_modified", data: @obj)
|
|
75
|
+
rescue StandardError => e
|
|
76
|
+
render_error(errors: e.message, status: :unprocessable_entity)
|
|
77
|
+
end
|
|
78
|
+
|
|
26
79
|
private
|
|
27
80
|
|
|
28
81
|
def model_params
|
|
29
82
|
params.require(:agent).permit(
|
|
30
|
-
:name, :phone, :service_area, :fayda_number, :photo, :onboarded_by_id
|
|
83
|
+
:name, :phone, :service_area, :sub_city, :woreda, :fayda_number, :photo, :onboarded_by_id
|
|
31
84
|
)
|
|
32
85
|
end
|
|
33
86
|
|
|
34
87
|
# Registration allows same fields but no authentication required
|
|
35
88
|
def registration_params
|
|
36
89
|
params.require(:agent).permit(
|
|
37
|
-
:name, :phone, :service_area, :fayda_number, :onboarded_by_id
|
|
90
|
+
:name, :phone, :service_area, :fayda_number, :onboarded_by_id,
|
|
91
|
+
:gender, :national_id
|
|
92
|
+
)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def create_registration_notification(agent)
|
|
96
|
+
recipient = Dscf::Core::User.joins(:roles)
|
|
97
|
+
.where(dscf_core_roles: {code: "SUPER_ADMIN"})
|
|
98
|
+
.first || Dscf::Core::User.first
|
|
99
|
+
|
|
100
|
+
return unless recipient
|
|
101
|
+
|
|
102
|
+
Dscf::Core::Notification.create!(
|
|
103
|
+
notifiable: agent,
|
|
104
|
+
recipient: recipient,
|
|
105
|
+
notification_type: :general,
|
|
106
|
+
title: "New Agent Registration",
|
|
107
|
+
body: "Agent '#{agent.name}' (#{agent.code}) has registered and is pending review. Phone: #{agent.phone}, Area: #{agent.service_area}"
|
|
38
108
|
)
|
|
39
109
|
end
|
|
40
110
|
|
|
41
111
|
def eager_loaded_associations
|
|
42
|
-
[:onboarded_by]
|
|
112
|
+
[ :onboarded_by ]
|
|
43
113
|
end
|
|
44
114
|
|
|
45
115
|
def default_serializer_includes
|
|
46
116
|
{
|
|
47
|
-
index: [:onboarded_by],
|
|
48
|
-
show: [:onboarded_by]
|
|
117
|
+
index: [ :onboarded_by ],
|
|
118
|
+
show: [ :onboarded_by ]
|
|
49
119
|
}
|
|
50
120
|
end
|
|
51
121
|
|
|
@@ -9,7 +9,7 @@ module Dscf
|
|
|
9
9
|
|
|
10
10
|
options = {
|
|
11
11
|
include: default_serializer_includes[:index] || [],
|
|
12
|
-
meta: {
|
|
12
|
+
meta: {resource_type: "aggregator_feed"}
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
render_success(data: listings, serializer_options: options)
|
|
@@ -22,7 +22,7 @@ module Dscf
|
|
|
22
22
|
|
|
23
23
|
options = {
|
|
24
24
|
include: default_serializer_includes[:index] || [],
|
|
25
|
-
meta: {
|
|
25
|
+
meta: {resource_type: "my_aggregator_listings"}
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
render_success(data: listings, serializer_options: options)
|
|
@@ -7,11 +7,11 @@ module Dscf
|
|
|
7
7
|
super do
|
|
8
8
|
if params[:delivery_order_id]
|
|
9
9
|
stops = DeliveryStop.where(delivery_order_id: params[:delivery_order_id])
|
|
10
|
-
options = {
|
|
11
|
-
[stops, options]
|
|
10
|
+
options = {include: [ :dropoff_address, :delivery_order_items ]}
|
|
11
|
+
[ stops, options ]
|
|
12
12
|
else
|
|
13
13
|
# Fallback or standard index if needed, though mostly used nested
|
|
14
|
-
[DeliveryStop.all, {}]
|
|
14
|
+
[ DeliveryStop.all, {} ]
|
|
15
15
|
end
|
|
16
16
|
end
|
|
17
17
|
end
|
|
@@ -21,8 +21,8 @@ module Dscf
|
|
|
21
21
|
authorize @delivery_stop, :verify?
|
|
22
22
|
if @delivery_stop.verify!(verified_by: current_user.id)
|
|
23
23
|
render_success(
|
|
24
|
-
data: @delivery_stop,
|
|
25
|
-
serializer_options: {
|
|
24
|
+
data: @delivery_stop,
|
|
25
|
+
serializer_options: {include: [ :dropoff_address, :delivery_order_items ]}
|
|
26
26
|
)
|
|
27
27
|
else
|
|
28
28
|
render_error(
|
|
@@ -39,7 +39,7 @@ module Dscf
|
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
def eager_loaded_associations
|
|
42
|
-
[:dropoff_address, :delivery_order_items]
|
|
42
|
+
[ :dropoff_address, :delivery_order_items ]
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
def allowed_order_columns
|
|
@@ -48,9 +48,9 @@ module Dscf
|
|
|
48
48
|
|
|
49
49
|
def default_serializer_includes
|
|
50
50
|
{
|
|
51
|
-
index: [:dropoff_address, :delivery_order_items],
|
|
52
|
-
show: [:dropoff_address, :delivery_order_items],
|
|
53
|
-
verify: [:dropoff_address, :delivery_order_items]
|
|
51
|
+
index: [ :dropoff_address, :delivery_order_items ],
|
|
52
|
+
show: [ :dropoff_address, :delivery_order_items ],
|
|
53
|
+
verify: [ :dropoff_address, :delivery_order_items ]
|
|
54
54
|
}
|
|
55
55
|
end
|
|
56
56
|
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
module Dscf
|
|
2
|
+
module Marketplace
|
|
3
|
+
class ListingApprovalsController < ApplicationController
|
|
4
|
+
include Dscf::Core::Common
|
|
5
|
+
|
|
6
|
+
def set_price
|
|
7
|
+
set_object
|
|
8
|
+
authorize @obj, :set_price?
|
|
9
|
+
|
|
10
|
+
if @obj.update(set_price_params.merge(approved_by: current_user, approved_at: Time.current))
|
|
11
|
+
notification = Dscf::Core::Notification.create!(
|
|
12
|
+
notification_type: :listing,
|
|
13
|
+
title: "Price set for listing ##{@obj.listing_id}",
|
|
14
|
+
body: "Aggregator price: #{@obj.aggregator_price}, Supplier price: #{@obj.supplier_price}",
|
|
15
|
+
recipient: current_user,
|
|
16
|
+
notifiable: @obj
|
|
17
|
+
)
|
|
18
|
+
Dscf::Core::NotificationService.deliver(notification)
|
|
19
|
+
render_success(data: @obj, serializer_options: {include: serializer_includes_for_action(:show)})
|
|
20
|
+
else
|
|
21
|
+
render_error(errors: @obj.errors.full_messages[0], status: :unprocessable_entity)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def model_params
|
|
28
|
+
params.require(:listing_approval).permit(
|
|
29
|
+
:listing_id, :aggregator_price, :supplier_price, :approval_status
|
|
30
|
+
)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def set_price_params
|
|
34
|
+
params.require(:listing_approval).permit(
|
|
35
|
+
:aggregator_price, :supplier_price, :approval_status
|
|
36
|
+
)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def eager_loaded_associations
|
|
40
|
+
[ :listing, :approved_by ]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def default_serializer_includes
|
|
44
|
+
{
|
|
45
|
+
index: [ :listing ],
|
|
46
|
+
show: [ :listing, :approved_by ],
|
|
47
|
+
create: [ :listing ],
|
|
48
|
+
update: [ :listing ]
|
|
49
|
+
}
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def allowed_order_columns
|
|
53
|
+
%w[id listing_id approval_status aggregator_price supplier_price approved_at created_at updated_at]
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -68,7 +68,7 @@ module Dscf
|
|
|
68
68
|
|
|
69
69
|
options = {
|
|
70
70
|
include: default_serializer_includes[:index] || [],
|
|
71
|
-
meta: {
|
|
71
|
+
meta: {resource_type: "visible_listings"}
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
render_success(data: listings, serializer_options: options)
|
|
@@ -81,7 +81,7 @@ module Dscf
|
|
|
81
81
|
|
|
82
82
|
options = {
|
|
83
83
|
include: default_serializer_includes[:index] || [],
|
|
84
|
-
meta: {
|
|
84
|
+
meta: {resource_type: "my_listings"}
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
render_success("listings.success.index", data: listings, serializer_options: options)
|
|
@@ -70,7 +70,7 @@ module Dscf
|
|
|
70
70
|
@obj.order_items.update_all(status: OrderItem.statuses[:fulfilled])
|
|
71
71
|
begin
|
|
72
72
|
invoice = Dscf::Marketplace::InvoicePdfGenerator.new(@obj).generate!
|
|
73
|
-
render_success("orders.success.completed", data: @obj, meta: {
|
|
73
|
+
render_success("orders.success.completed", data: @obj, meta: {invoice_id: invoice.id})
|
|
74
74
|
rescue => e
|
|
75
75
|
Rails.logger.error("Invoice generation failed for order #{@obj.id}: #{e.message}")
|
|
76
76
|
render_success("orders.success.completed", data: @obj)
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
module Dscf
|
|
2
|
+
module Marketplace
|
|
3
|
+
class ProductInclusionRequestsController < ApplicationController
|
|
4
|
+
include Dscf::Core::Common
|
|
5
|
+
|
|
6
|
+
# Override create to set requested_by from current_user
|
|
7
|
+
def create
|
|
8
|
+
authorize @clazz.new, :create?
|
|
9
|
+
|
|
10
|
+
obj = @clazz.new(model_params)
|
|
11
|
+
obj.requested_by = current_user
|
|
12
|
+
|
|
13
|
+
ActiveRecord::Base.transaction do
|
|
14
|
+
if obj.save
|
|
15
|
+
@obj = obj
|
|
16
|
+
after_save_hook(obj) if respond_to?(:after_save_hook, true)
|
|
17
|
+
|
|
18
|
+
obj = @clazz.includes(eager_loaded_associations).find(obj.id) if eager_loaded_associations.present?
|
|
19
|
+
@obj = obj
|
|
20
|
+
|
|
21
|
+
includes = serializer_includes_for_action(:create)
|
|
22
|
+
options = {}
|
|
23
|
+
options[:include] = includes if includes.present?
|
|
24
|
+
|
|
25
|
+
render_success(data: obj, serializer_options: options, status: :created)
|
|
26
|
+
else
|
|
27
|
+
render_error(errors: obj.errors.full_messages[0], status: :unprocessable_entity)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
rescue ::Pundit::NotAuthorizedError
|
|
31
|
+
raise
|
|
32
|
+
rescue Dscf::Core::FileUploadError => e
|
|
33
|
+
render_error(errors: e.message, status: :unprocessable_entity)
|
|
34
|
+
rescue StandardError => e
|
|
35
|
+
render_error(error: e.message)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Approve a pending product inclusion request
|
|
39
|
+
def approve
|
|
40
|
+
set_object
|
|
41
|
+
authorize @obj, :approve?
|
|
42
|
+
|
|
43
|
+
@obj.approve!(current_user)
|
|
44
|
+
create_notification(:approved)
|
|
45
|
+
|
|
46
|
+
render_success("product_inclusion_requests.success.approve", data: @obj)
|
|
47
|
+
rescue StandardError => e
|
|
48
|
+
render_error(errors: e.message, status: :unprocessable_entity)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Request modification with a review comment
|
|
52
|
+
def modify
|
|
53
|
+
set_object
|
|
54
|
+
authorize @obj, :modify?
|
|
55
|
+
|
|
56
|
+
comment = params[:review_comment]
|
|
57
|
+
raise ArgumentError, "Review comment is required for modification" if comment.blank?
|
|
58
|
+
|
|
59
|
+
@obj.modify!(current_user, comment)
|
|
60
|
+
create_notification(:modification)
|
|
61
|
+
|
|
62
|
+
render_success("product_inclusion_requests.success.modify", data: @obj)
|
|
63
|
+
rescue ArgumentError => e
|
|
64
|
+
render_error(errors: e.message, status: :unprocessable_entity)
|
|
65
|
+
rescue StandardError => e
|
|
66
|
+
render_error(errors: e.message, status: :unprocessable_entity)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Decline a pending product inclusion request
|
|
70
|
+
def decline
|
|
71
|
+
set_object
|
|
72
|
+
authorize @obj, :decline?
|
|
73
|
+
|
|
74
|
+
comment = params[:review_comment]
|
|
75
|
+
raise ArgumentError, "Review comment is required for decline" if comment.blank?
|
|
76
|
+
|
|
77
|
+
@obj.decline!(current_user, comment)
|
|
78
|
+
create_notification(:rejection)
|
|
79
|
+
|
|
80
|
+
render_success("product_inclusion_requests.success.decline", data: @obj)
|
|
81
|
+
rescue ArgumentError => e
|
|
82
|
+
render_error(errors: e.message, status: :unprocessable_entity)
|
|
83
|
+
rescue StandardError => e
|
|
84
|
+
render_error(errors: e.message, status: :unprocessable_entity)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
private
|
|
88
|
+
|
|
89
|
+
def model_params
|
|
90
|
+
params.require(:product_inclusion_request).permit(
|
|
91
|
+
:supplier_id, :product_name, :product_description, :unit_of_measure,
|
|
92
|
+
product_images: []
|
|
93
|
+
)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def eager_loaded_associations
|
|
97
|
+
%i[supplier requested_by reviewer]
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def default_serializer_includes
|
|
101
|
+
{
|
|
102
|
+
index: %i[supplier requested_by],
|
|
103
|
+
show: %i[supplier requested_by reviewer],
|
|
104
|
+
create: %i[supplier requested_by],
|
|
105
|
+
update: %i[supplier requested_by]
|
|
106
|
+
}
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def create_notification(action_type)
|
|
110
|
+
notification_type = case action_type
|
|
111
|
+
when :approved then :approval
|
|
112
|
+
when :modification then :modification
|
|
113
|
+
when :rejection then :rejection
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
notification = Dscf::Core::Notification.create!(
|
|
117
|
+
notifiable: @obj,
|
|
118
|
+
recipient: @obj.requested_by,
|
|
119
|
+
notification_type: notification_type,
|
|
120
|
+
title: "Product Inclusion Request #{action_type.to_s.humanize}",
|
|
121
|
+
body: "Your product inclusion request for '#{@obj.product_name}' has been #{action_type.to_s.humanize.downcase}."
|
|
122
|
+
)
|
|
123
|
+
Dscf::Core::NotificationService.deliver(notification)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
module Dscf
|
|
2
|
+
module Marketplace
|
|
3
|
+
class RetailersController < ApplicationController
|
|
4
|
+
include Dscf::Core::Common
|
|
5
|
+
|
|
6
|
+
skip_before_action :authenticate_user, only: [ :register ]
|
|
7
|
+
|
|
8
|
+
def register
|
|
9
|
+
ActiveRecord::Base.transaction do
|
|
10
|
+
user = Dscf::Core::User.new(
|
|
11
|
+
phone: registration_params[:phone],
|
|
12
|
+
password: registration_params[:password],
|
|
13
|
+
password_confirmation: registration_params[:password_confirmation]
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
retailer = Dscf::Marketplace::Retailer.new(
|
|
17
|
+
name: registration_params[:name],
|
|
18
|
+
phone: registration_params[:phone],
|
|
19
|
+
tin_number: registration_params[:tin_number],
|
|
20
|
+
location: registration_params[:location],
|
|
21
|
+
status: :active
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
user.save!
|
|
25
|
+
retailer.save!
|
|
26
|
+
|
|
27
|
+
render_success("retailers.success.register", data: retailer, status: :created)
|
|
28
|
+
end
|
|
29
|
+
rescue ActiveRecord::RecordInvalid, ActiveRecord::RecordNotSaved => e
|
|
30
|
+
errors = e.respond_to?(:record) && e.record ? e.record.errors.full_messages : [ e.message ]
|
|
31
|
+
render_error("retailers.errors.register", errors: errors, status: :unprocessable_entity)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def my_retailers
|
|
35
|
+
authorize @clazz.new, :index?
|
|
36
|
+
retailers = @clazz.where(agent_id: params[:agent_id])
|
|
37
|
+
|
|
38
|
+
options = {
|
|
39
|
+
include: default_serializer_includes[:index] || [],
|
|
40
|
+
meta: {resource_type: "my_retailers"}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
render_success("retailers.success.index", data: retailers, serializer_options: options)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
def model_params
|
|
49
|
+
params.require(:retailer).permit(
|
|
50
|
+
:name, :phone, :tin_number, :location, :agent_id
|
|
51
|
+
)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def registration_params
|
|
55
|
+
params.require(:retailer).permit(
|
|
56
|
+
:name, :phone, :tin_number, :location, :password, :password_confirmation
|
|
57
|
+
)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module Dscf
|
|
2
|
+
module Marketplace
|
|
3
|
+
class SubSuppliersController < ApplicationController
|
|
4
|
+
include Dscf::Core::Common
|
|
5
|
+
|
|
6
|
+
private
|
|
7
|
+
|
|
8
|
+
def model_params
|
|
9
|
+
params.require(:sub_supplier).permit(
|
|
10
|
+
:business_name, :contact_person_name, :contact_person_phone,
|
|
11
|
+
:city, :sub_city, :woreda, :supplier_id, :business_license
|
|
12
|
+
)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -48,7 +48,11 @@ module Dscf
|
|
|
48
48
|
set_object
|
|
49
49
|
authorize @obj, :approve?
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
update_params = {status: :active, approved_at: Time.current}
|
|
52
|
+
update_params[:rejection_reason] = params[:reason] if params[:reason].present?
|
|
53
|
+
|
|
54
|
+
if @obj.update(update_params)
|
|
55
|
+
create_notification(:approved)
|
|
52
56
|
render_success("supplier_products.success.approve", data: @obj)
|
|
53
57
|
else
|
|
54
58
|
render_error("supplier_products.errors.approve", errors: @obj.errors.full_messages, status: :unprocessable_entity)
|
|
@@ -60,11 +64,17 @@ module Dscf
|
|
|
60
64
|
set_object
|
|
61
65
|
authorize @obj, :approve?
|
|
62
66
|
|
|
63
|
-
|
|
67
|
+
reason = params[:reason]
|
|
68
|
+
raise ArgumentError, "Reason is required for rejection" if reason.blank?
|
|
69
|
+
|
|
70
|
+
if @obj.update(status: :inactive, rejection_reason: reason, rejected_at: Time.current)
|
|
71
|
+
create_notification(:rejected)
|
|
64
72
|
render_success("supplier_products.success.reject", data: @obj)
|
|
65
73
|
else
|
|
66
74
|
render_error("supplier_products.errors.reject", errors: @obj.errors.full_messages, status: :unprocessable_entity)
|
|
67
75
|
end
|
|
76
|
+
rescue ArgumentError => e
|
|
77
|
+
render_error(errors: e.message, status: :unprocessable_entity)
|
|
68
78
|
end
|
|
69
79
|
|
|
70
80
|
private
|
|
@@ -76,6 +86,21 @@ module Dscf
|
|
|
76
86
|
)
|
|
77
87
|
end
|
|
78
88
|
|
|
89
|
+
def create_notification(action_type)
|
|
90
|
+
notification_type = case action_type
|
|
91
|
+
when :approved then :approval
|
|
92
|
+
when :rejected then :rejection
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
Dscf::Core::Notification.create!(
|
|
96
|
+
notifiable: @obj,
|
|
97
|
+
recipient: @obj.business.user,
|
|
98
|
+
notification_type: notification_type,
|
|
99
|
+
title: "Supplier Product #{action_type.to_s.humanize}",
|
|
100
|
+
body: "Your supplier product '#{@obj.display_name}' has been #{action_type.to_s.humanize.downcase}."
|
|
101
|
+
)
|
|
102
|
+
end
|
|
103
|
+
|
|
79
104
|
def eager_loaded_associations
|
|
80
105
|
[ :business, :product, :supplier, :listings ]
|
|
81
106
|
end
|