dscf-marketplace 0.7.0 → 0.7.2

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 (34) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/dscf/marketplace/application_controller.rb +1 -3
  3. data/app/controllers/dscf/marketplace/delivery_order_items_controller.rb +3 -0
  4. data/app/controllers/dscf/marketplace/delivery_orders_controller.rb +10 -0
  5. data/app/controllers/dscf/marketplace/delivery_stops_controller.rb +1 -0
  6. data/app/controllers/dscf/marketplace/delivery_vehicles_controller.rb +2 -0
  7. data/app/controllers/dscf/marketplace/listings_controller.rb +5 -0
  8. data/app/controllers/dscf/marketplace/orders_controller.rb +5 -0
  9. data/app/controllers/dscf/marketplace/products_controller.rb +1 -0
  10. data/app/controllers/dscf/marketplace/quotations_controller.rb +5 -0
  11. data/app/controllers/dscf/marketplace/request_for_quotations_controller.rb +6 -0
  12. data/app/controllers/dscf/marketplace/supplier_products_controller.rb +1 -0
  13. data/app/policies/dscf/marketplace/category_policy.rb +6 -0
  14. data/app/policies/dscf/marketplace/delivery_order_item_policy.rb +17 -0
  15. data/app/policies/dscf/marketplace/delivery_order_policy.rb +41 -0
  16. data/app/policies/dscf/marketplace/delivery_stop_policy.rb +9 -0
  17. data/app/policies/dscf/marketplace/delivery_vehicle_policy.rb +6 -0
  18. data/app/policies/dscf/marketplace/listing_policy.rb +25 -0
  19. data/app/policies/dscf/marketplace/location_policy.rb +9 -0
  20. data/app/policies/dscf/marketplace/order_item_policy.rb +6 -0
  21. data/app/policies/dscf/marketplace/order_policy.rb +25 -0
  22. data/app/policies/dscf/marketplace/product_policy.rb +13 -0
  23. data/app/policies/dscf/marketplace/quotation_item_policy.rb +6 -0
  24. data/app/policies/dscf/marketplace/quotation_policy.rb +25 -0
  25. data/app/policies/dscf/marketplace/request_for_quotation_policy.rb +25 -0
  26. data/app/policies/dscf/marketplace/rfq_item_policy.rb +6 -0
  27. data/app/policies/dscf/marketplace/supplier_product_policy.rb +9 -0
  28. data/app/policies/dscf/marketplace/unit_conversion_policy.rb +6 -0
  29. data/app/policies/dscf/marketplace/unit_policy.rb +6 -0
  30. data/db/migrate/20260310120000_add_active_and_description_to_dscf_core_roles.rb +8 -0
  31. data/db/migrate/20260310122000_add_missing_fields_to_dscf_core_user_roles.rb +10 -0
  32. data/db/seeds.rb +34 -339
  33. data/lib/dscf/marketplace/version.rb +1 -1
  34. metadata +20 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 873ebd62a895e7774b5c0f235b4469258c7160516bd99e829897ceb586b3ff3f
4
- data.tar.gz: 5a442910c89af40c3e610eb4df050f567250e225df5c5985926ddc8d86dba8db
3
+ metadata.gz: 81c4fc2b3cbb08308f4da22f26a56d9d7a3ca197325c340d491dacfe4adbaa6f
4
+ data.tar.gz: 1c89213f1171138ea6efc0c8566a60a6937348c7c934cfacc8ccecd53f35c310
5
5
  SHA512:
6
- metadata.gz: 48fcf67a12f75cfbc5242011a1040af3d51c0dd1db54f4be7a06555717b49047072d00a8b16b4500f24ec225cbc7a70f55389eb2bbc977ad51f35b1f318fc85a
7
- data.tar.gz: 9f2757a6957338c87e16d79290b78e118f350c50bf3f7e567f300af5fd67c7bbf1538d47b6c5d2887e1f3e82b706025d5be2d4007d478260434c335581e14c90
6
+ metadata.gz: 2f812ce7f37138fbf88cfed6c03233193b12fef8a194f8cd632c8006b86814201af5877122679c9634920bcb4ba73291e7ea2171009be15265a38cd9dad524c5
7
+ data.tar.gz: e6ffd5232a4f43d7d4020f789a0ce6b400858ffd2801192a7008dab0ffd4f66f3dcd3488c0364f26d8861c2b451eb2d6f1f2edcfbd9b990363cd121b6905a3b6
@@ -1,8 +1,6 @@
1
1
  module Dscf
2
2
  module Marketplace
3
- class ApplicationController < ActionController::API
4
- include Dscf::Core::JsonResponse
5
- include Dscf::Core::Authenticatable
3
+ class ApplicationController < Dscf::Core::ApplicationController
6
4
  end
7
5
  end
8
6
  end
@@ -5,6 +5,7 @@ module Dscf
5
5
 
6
6
  def receiver_confirm
7
7
  @obj = find_record
8
+ authorize @obj, :receiver_confirm?
8
9
  if @obj.receiver_confirm!(params[:confirmed_quantity], params[:notes], current_user&.id)
9
10
  render_success("delivery_order_items.success.receiver_confirmed", data: @obj)
10
11
  else
@@ -14,6 +15,7 @@ module Dscf
14
15
 
15
16
  def report_issue
16
17
  @obj = find_record
18
+ authorize @obj, :report_issue?
17
19
  issue_type = params[:issue_type]
18
20
  quantity = params[:quantity]
19
21
  description = params[:description]
@@ -27,6 +29,7 @@ module Dscf
27
29
 
28
30
  def dispute_delivery
29
31
  @obj = find_record
32
+ authorize @obj, :dispute_delivery?
30
33
  reason = params[:reason]
31
34
 
32
35
  if @obj.dispute_delivery!(reason, current_user&.id)
@@ -4,6 +4,7 @@ module Dscf
4
4
  include Dscf::Core::Common
5
5
 
6
6
  def index
7
+ authorize @clazz.new, :index?
7
8
  # Custom implementation to avoid JSON field issues
8
9
  delivery_orders = @clazz.all
9
10
 
@@ -46,6 +47,7 @@ module Dscf
46
47
  end
47
48
 
48
49
  def filter
50
+ authorize @clazz.new, :filter?
49
51
  delivery_orders = @clazz.all
50
52
 
51
53
  # Apply Ransack filtering if q params present
@@ -70,11 +72,13 @@ module Dscf
70
72
 
71
73
  def summary
72
74
  @delivery_order = find_record
75
+ authorize @delivery_order, :summary?
73
76
  render_success(data: @delivery_order.generate_handoff_summary_report)
74
77
  end
75
78
 
76
79
  def pickup
77
80
  @obj = find_record
81
+ authorize @obj, :pickup?
78
82
  if @obj.pickup!
79
83
  render_success("delivery_orders.success.picked_up", data: @obj)
80
84
  else
@@ -84,6 +88,7 @@ module Dscf
84
88
 
85
89
  def start_delivery
86
90
  @obj = find_record
91
+ authorize @obj, :start_delivery?
87
92
  if @obj.start_delivery!
88
93
  render_success("delivery_orders.success.delivery_started", data: @obj)
89
94
  else
@@ -93,6 +98,7 @@ module Dscf
93
98
 
94
99
  def complete_delivery
95
100
  @obj = find_record
101
+ authorize @obj, :complete_delivery?
96
102
  if @obj.complete_delivery!
97
103
  render_success("delivery_orders.success.delivery_completed", data: @obj)
98
104
  else
@@ -102,6 +108,7 @@ module Dscf
102
108
 
103
109
  def mark_failed
104
110
  @obj = find_record
111
+ authorize @obj, :mark_failed?
105
112
  reason = params[:reason]
106
113
  if @obj.mark_failed!(reason)
107
114
  render_success("delivery_orders.success.marked_failed", data: @obj)
@@ -112,6 +119,7 @@ module Dscf
112
119
 
113
120
  def accept
114
121
  @obj = find_record
122
+ authorize @obj, :accept?
115
123
  service = Dscf::Marketplace::DeliveryOrderService.new
116
124
  begin
117
125
  service.assign_driver(@obj, current_user)
@@ -126,6 +134,7 @@ module Dscf
126
134
  end
127
135
 
128
136
  def convert_orders
137
+ authorize @clazz.new, :convert_orders?
129
138
  order_ids = params[:order_ids]
130
139
  vehicle_type = params[:vehicle_type]
131
140
  pickup_address_id = params[:pickup_address_id]
@@ -165,6 +174,7 @@ module Dscf
165
174
  end
166
175
 
167
176
  def my_driver_deliveries
177
+ authorize @clazz.new, :my_driver_deliveries?
168
178
  # Verify user has driver role
169
179
  unless Dscf::Marketplace::RoleService.user_has_driver_role?(current_user)
170
180
  render_error("delivery_orders.errors.access_denied", message: "Only drivers can access this endpoint")
@@ -18,6 +18,7 @@ module Dscf
18
18
 
19
19
  def verify
20
20
  @delivery_stop = DeliveryStop.find(params[:id])
21
+ authorize @delivery_stop, :verify?
21
22
  if @delivery_stop.verify!(verified_by: current_user.id)
22
23
  render_success(
23
24
  data: @delivery_stop,
@@ -4,6 +4,7 @@ module Dscf
4
4
  include Dscf::Core::Common
5
5
 
6
6
  def create
7
+ authorize @clazz.new, :create?
7
8
  vehicle = @clazz.new(model_params.except(:vehicle_license, :driver_license))
8
9
  if vehicle.save
9
10
  # Auto-assign Driver role to the vehicle's driver
@@ -42,6 +43,7 @@ module Dscf
42
43
 
43
44
  def update
44
45
  vehicle = @clazz.find(params[:id])
46
+ authorize vehicle, :update?
45
47
  if vehicle.update(model_params.except(:vehicle_license, :driver_license))
46
48
  # Handle vehicle license update/replacement
47
49
  if params[:delivery_vehicle][:vehicle_license].present?
@@ -5,6 +5,7 @@ module Dscf
5
5
 
6
6
  def activate
7
7
  @obj = find_record
8
+ authorize @obj, :activate?
8
9
  if @obj.update(status: :active)
9
10
  render_success("listings.success.activated", data: @obj)
10
11
  else
@@ -14,6 +15,7 @@ module Dscf
14
15
 
15
16
  def pause
16
17
  @obj = find_record
18
+ authorize @obj, :pause?
17
19
  if @obj.update(status: :paused)
18
20
  render_success("listings.success.paused", data: @obj)
19
21
  else
@@ -23,6 +25,7 @@ module Dscf
23
25
 
24
26
  def sold_out
25
27
  @obj = find_record
28
+ authorize @obj, :sold_out?
26
29
  if @obj.update(status: :sold_out)
27
30
  render_success("listings.success.sold_out", data: @obj)
28
31
  else
@@ -31,6 +34,7 @@ module Dscf
31
34
  end
32
35
 
33
36
  def my_listings
37
+ authorize @clazz.new, :my_listings?
34
38
  service = MyResourceService.new(current_user)
35
39
  listings = service.my_listings(params)
36
40
 
@@ -43,6 +47,7 @@ module Dscf
43
47
  end
44
48
 
45
49
  def listings_by_supplier
50
+ authorize @clazz.new, :listings_by_supplier?
46
51
  supplier_id = params[:supplier_id]
47
52
 
48
53
  # Validate supplier exists
@@ -4,6 +4,7 @@ module Dscf
4
4
  include Dscf::Core::Common
5
5
 
6
6
  def filter
7
+ authorize @clazz.new, :filter?
7
8
  orders = @clazz.all
8
9
 
9
10
  # Apply Ransack filtering if q params present
@@ -24,6 +25,7 @@ module Dscf
24
25
 
25
26
  def confirm
26
27
  @obj = find_record
28
+ authorize @obj, :confirm?
27
29
  if @obj.confirm!
28
30
  render_success("orders.success.confirmed", data: @obj)
29
31
  else
@@ -33,6 +35,7 @@ module Dscf
33
35
 
34
36
  def cancel
35
37
  @obj = find_record
38
+ authorize @obj, :cancel?
36
39
  if @obj.update(status: :cancelled)
37
40
  @obj.order_items.update_all(status: OrderItem.statuses[:cancelled])
38
41
  render_success("orders.success.cancelled", data: @obj)
@@ -43,6 +46,7 @@ module Dscf
43
46
 
44
47
  def complete
45
48
  @obj = find_record
49
+ authorize @obj, :complete?
46
50
  if @obj.can_be_completed? && @obj.update(status: :completed)
47
51
  @obj.order_items.update_all(status: OrderItem.statuses[:completed])
48
52
  render_success("orders.success.completed", data: @obj)
@@ -52,6 +56,7 @@ module Dscf
52
56
  end
53
57
 
54
58
  def my_orders
59
+ authorize @clazz.new, :my_orders?
55
60
  service = MyResourceService.new(current_user)
56
61
  orders = service.my_orders(params)
57
62
 
@@ -4,6 +4,7 @@ module Dscf
4
4
  include Dscf::Core::Common
5
5
 
6
6
  def filter
7
+ authorize @clazz.new, :filter?
7
8
  products = @clazz.all
8
9
 
9
10
  # Apply Ransack filtering if q params present
@@ -4,6 +4,7 @@ module Dscf
4
4
  include Dscf::Core::Common
5
5
 
6
6
  def filter
7
+ authorize @clazz.new, :filter?
7
8
  quotations = @clazz.all
8
9
 
9
10
  # Apply Ransack filtering if q params present
@@ -24,6 +25,7 @@ module Dscf
24
25
 
25
26
  def accept
26
27
  @obj = find_record
28
+ authorize @obj, :accept?
27
29
 
28
30
  fulfillment_type = params[:fulfillment_type]
29
31
  dropoff_address_id = params[:dropoff_address_id]
@@ -57,6 +59,7 @@ module Dscf
57
59
 
58
60
  def reject
59
61
  @obj = find_record
62
+ authorize @obj, :reject?
60
63
  if @obj.reject!
61
64
  render_success("quotations.success.rejected", data: @obj)
62
65
  else
@@ -66,6 +69,7 @@ module Dscf
66
69
 
67
70
  def send_quotation
68
71
  @obj = find_record
72
+ authorize @obj, :send_quotation?
69
73
  if @obj.send_quotation!
70
74
  render_success("quotations.success.sent", data: @obj)
71
75
  else
@@ -74,6 +78,7 @@ module Dscf
74
78
  end
75
79
 
76
80
  def my_quotes
81
+ authorize @clazz.new, :my_quotes?
77
82
  service = MyResourceService.new(current_user)
78
83
  quotes = service.my_quotes(params)
79
84
 
@@ -4,6 +4,7 @@ module Dscf
4
4
  include Dscf::Core::Common
5
5
 
6
6
  def filter
7
+ authorize @clazz.new, :filter?
7
8
  rfqs = @clazz.all
8
9
 
9
10
  # Apply Ransack filtering if q params present
@@ -23,6 +24,7 @@ module Dscf
23
24
  end
24
25
 
25
26
  def create
27
+ authorize @clazz.new, :create?
26
28
  obj = @clazz.new(model_params)
27
29
  if obj.save
28
30
  obj = @clazz.includes(eager_loaded_associations).find(obj.id) if eager_loaded_associations.present?
@@ -41,6 +43,7 @@ module Dscf
41
43
 
42
44
  def send_rfq
43
45
  @obj = find_record
46
+ authorize @obj, :send_rfq?
44
47
  if @obj.draft? && @obj.update(status: :sent)
45
48
  render_success("request_for_quotations.success.sent", data: @obj)
46
49
  else
@@ -50,6 +53,7 @@ module Dscf
50
53
 
51
54
  def close
52
55
  @obj = find_record
56
+ authorize @obj, :close?
53
57
  if (@obj.sent? || @obj.responded?) && @obj.update(status: :closed)
54
58
  render_success("request_for_quotations.success.closed", data: @obj)
55
59
  else
@@ -58,6 +62,7 @@ module Dscf
58
62
  end
59
63
 
60
64
  def my_rfqs
65
+ authorize @clazz.new, :my_rfqs?
61
66
  service = MyResourceService.new(current_user)
62
67
  rfqs = service.my_rfqs(params)
63
68
 
@@ -71,6 +76,7 @@ module Dscf
71
76
 
72
77
  def respond
73
78
  @rfq = Dscf::Marketplace::RequestForQuotation.find(params[:id])
79
+ authorize @rfq, :respond?
74
80
  service = RfqResponseService.new(current_user)
75
81
  result = service.respond_to_rfq(@rfq, params.permit(:notes, :valid_until, :delivery_date, quotation_items_attributes: [ :rfq_item_id, :unit_id, :quantity, :unit_price, :notes ]))
76
82
 
@@ -4,6 +4,7 @@ module Dscf
4
4
  include Dscf::Core::Common
5
5
 
6
6
  def my_products
7
+ authorize @clazz.new, :my_products?
7
8
  service = MyResourceService.new(current_user)
8
9
  products = service.my_products(params)
9
10
 
@@ -0,0 +1,6 @@
1
+ module Dscf
2
+ module Marketplace
3
+ class CategoryPolicy < Dscf::Core::ApplicationPolicy
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,17 @@
1
+ module Dscf
2
+ module Marketplace
3
+ class DeliveryOrderItemPolicy < Dscf::Core::ApplicationPolicy
4
+ def receiver_confirm?
5
+ user.has_permission?("delivery_order_items.receiver_confirm")
6
+ end
7
+
8
+ def report_issue?
9
+ user.has_permission?("delivery_order_items.report_issue")
10
+ end
11
+
12
+ def dispute_delivery?
13
+ user.has_permission?("delivery_order_items.dispute_delivery")
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,41 @@
1
+ module Dscf
2
+ module Marketplace
3
+ class DeliveryOrderPolicy < Dscf::Core::ApplicationPolicy
4
+ def filter?
5
+ user.has_permission?("delivery_orders.filter")
6
+ end
7
+
8
+ def summary?
9
+ user.has_permission?("delivery_orders.summary")
10
+ end
11
+
12
+ def pickup?
13
+ user.has_permission?("delivery_orders.pickup")
14
+ end
15
+
16
+ def start_delivery?
17
+ user.has_permission?("delivery_orders.start_delivery")
18
+ end
19
+
20
+ def complete_delivery?
21
+ user.has_permission?("delivery_orders.complete_delivery")
22
+ end
23
+
24
+ def mark_failed?
25
+ user.has_permission?("delivery_orders.mark_failed")
26
+ end
27
+
28
+ def accept?
29
+ user.has_permission?("delivery_orders.accept")
30
+ end
31
+
32
+ def convert_orders?
33
+ user.has_permission?("delivery_orders.convert_orders")
34
+ end
35
+
36
+ def my_driver_deliveries?
37
+ user.has_permission?("delivery_orders.my_driver_deliveries")
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,9 @@
1
+ module Dscf
2
+ module Marketplace
3
+ class DeliveryStopPolicy < Dscf::Core::ApplicationPolicy
4
+ def verify?
5
+ user.has_permission?("delivery_stops.verify")
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,6 @@
1
+ module Dscf
2
+ module Marketplace
3
+ class DeliveryVehiclePolicy < Dscf::Core::ApplicationPolicy
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,25 @@
1
+ module Dscf
2
+ module Marketplace
3
+ class ListingPolicy < Dscf::Core::ApplicationPolicy
4
+ def activate?
5
+ user.has_permission?("listings.activate")
6
+ end
7
+
8
+ def pause?
9
+ user.has_permission?("listings.pause")
10
+ end
11
+
12
+ def sold_out?
13
+ user.has_permission?("listings.sold_out")
14
+ end
15
+
16
+ def my_listings?
17
+ user.has_permission?("listings.my_listings")
18
+ end
19
+
20
+ def listings_by_supplier?
21
+ user.has_permission?("listings.listings_by_supplier")
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,9 @@
1
+ module Dscf
2
+ module Marketplace
3
+ class LocationPolicy < Dscf::Core::ApplicationPolicy
4
+ def get_location?
5
+ user.has_permission?("locations.get_location")
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,6 @@
1
+ module Dscf
2
+ module Marketplace
3
+ class OrderItemPolicy < Dscf::Core::ApplicationPolicy
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,25 @@
1
+ module Dscf
2
+ module Marketplace
3
+ class OrderPolicy < Dscf::Core::ApplicationPolicy
4
+ def filter?
5
+ user.has_permission?("orders.filter")
6
+ end
7
+
8
+ def confirm?
9
+ user.has_permission?("orders.confirm")
10
+ end
11
+
12
+ def cancel?
13
+ user.has_permission?("orders.cancel")
14
+ end
15
+
16
+ def complete?
17
+ user.has_permission?("orders.complete")
18
+ end
19
+
20
+ def my_orders?
21
+ user.has_permission?("orders.my_orders")
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,13 @@
1
+ module Dscf
2
+ module Marketplace
3
+ class ProductPolicy < Dscf::Core::ApplicationPolicy
4
+ def filter?
5
+ user.has_permission?("products.filter")
6
+ end
7
+
8
+ def supplier_products?
9
+ user.has_permission?("products.supplier_products")
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,6 @@
1
+ module Dscf
2
+ module Marketplace
3
+ class QuotationItemPolicy < Dscf::Core::ApplicationPolicy
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,25 @@
1
+ module Dscf
2
+ module Marketplace
3
+ class QuotationPolicy < Dscf::Core::ApplicationPolicy
4
+ def filter?
5
+ user.has_permission?("quotations.filter")
6
+ end
7
+
8
+ def accept?
9
+ user.has_permission?("quotations.accept")
10
+ end
11
+
12
+ def reject?
13
+ user.has_permission?("quotations.reject")
14
+ end
15
+
16
+ def send_quotation?
17
+ user.has_permission?("quotations.send_quotation")
18
+ end
19
+
20
+ def my_quotes?
21
+ user.has_permission?("quotations.my_quotes")
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ module Dscf
2
+ module Marketplace
3
+ class RequestForQuotationPolicy < Dscf::Core::ApplicationPolicy
4
+ def filter?
5
+ user.has_permission?("request_for_quotations.filter")
6
+ end
7
+
8
+ def send_rfq?
9
+ user.has_permission?("request_for_quotations.send_rfq")
10
+ end
11
+
12
+ def close?
13
+ user.has_permission?("request_for_quotations.close")
14
+ end
15
+
16
+ def respond?
17
+ user.has_permission?("request_for_quotations.respond")
18
+ end
19
+
20
+ def my_rfqs?
21
+ user.has_permission?("request_for_quotations.my_rfqs")
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,6 @@
1
+ module Dscf
2
+ module Marketplace
3
+ class RfqItemPolicy < Dscf::Core::ApplicationPolicy
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,9 @@
1
+ module Dscf
2
+ module Marketplace
3
+ class SupplierProductPolicy < Dscf::Core::ApplicationPolicy
4
+ def my_products?
5
+ user.has_permission?("supplier_products.my_products")
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,6 @@
1
+ module Dscf
2
+ module Marketplace
3
+ class UnitConversionPolicy < Dscf::Core::ApplicationPolicy
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Dscf
2
+ module Marketplace
3
+ class UnitPolicy < Dscf::Core::ApplicationPolicy
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,8 @@
1
+ class AddActiveAndDescriptionToDscfCoreRoles < ActiveRecord::Migration[8.0]
2
+ def change
3
+ add_column :dscf_core_roles, :description, :string, if_not_exists: true
4
+ add_column :dscf_core_roles, :active, :boolean, null: false, default: true, if_not_exists: true
5
+
6
+ add_index :dscf_core_roles, :active, if_not_exists: true
7
+ end
8
+ end
@@ -0,0 +1,10 @@
1
+ class AddMissingFieldsToDscfCoreUserRoles < ActiveRecord::Migration[8.0]
2
+ def change
3
+ add_column :dscf_core_user_roles, :expires_at, :datetime, if_not_exists: true
4
+ add_index :dscf_core_user_roles, :expires_at, name: "expires_at_on_dc_ur_indx", if_not_exists: true
5
+
6
+ add_column :dscf_core_user_roles, :assigned_by_id, :bigint, if_not_exists: true
7
+ add_index :dscf_core_user_roles, :assigned_by_id, name: "assigned_by_on_dc_ur_indx", if_not_exists: true
8
+ add_foreign_key :dscf_core_user_roles, :dscf_core_users, column: :assigned_by_id, if_not_exists: true
9
+ end
10
+ end
data/db/seeds.rb CHANGED
@@ -1,343 +1,38 @@
1
- puts "🚀 Starting demo seed..."
2
- begin
3
- puts "🧹 Clearing existing demo data..."
4
- Dscf::Marketplace::DeliveryOrderItem.delete_all
5
- Dscf::Marketplace::DeliveryOrder.delete_all
6
- Dscf::Marketplace::OrderItem.delete_all
7
- Dscf::Marketplace::Order.delete_all
8
- Dscf::Marketplace::QuotationItem.delete_all
9
- Dscf::Marketplace::Quotation.delete_all
10
- Dscf::Marketplace::RfqItem.delete_all
11
- Dscf::Marketplace::RequestForQuotation.delete_all
12
- Dscf::Marketplace::Listing.delete_all
13
- Dscf::Marketplace::SupplierProduct.delete_all
14
- Dscf::Marketplace::Product.delete_all
15
- Dscf::Core::Business.delete_all
16
- Dscf::Core::User.where.not(email: "admin@example.com").delete_all
17
- Dscf::Core::Address.delete_all
18
-
19
- puts "🌱 Creating base units and categories..."
20
-
21
- # Units
22
- kg = Dscf::Marketplace::Unit.create!(name: "Kilogram", code: "kg", unit_type: :weight)
23
- Dscf::Marketplace::Unit.create!(name: "Piece", code: "pc", unit_type: :quantity)
24
- liter = Dscf::Marketplace::Unit.create!(name: "Liter", code: "L", unit_type: :volume)
25
-
26
- # Categories
27
- fruits_veg = Dscf::Marketplace::Category.create!(name: "Fruits & Vegetables")
28
- dairy = Dscf::Marketplace::Category.create!(name: "Dairy Products")
29
- Dscf::Marketplace::Category.create!(name: "Grains & Cereals")
30
- Dscf::Marketplace::Category.create!(name: "Beverages")
31
-
32
- puts "✅ Created #{Dscf::Marketplace::Unit.count} units and #{Dscf::Marketplace::Category.count} categories"
33
-
34
- puts "👥 Creating users and personas..."
35
-
36
- # Business Types
37
- wholesale_type = Dscf::Core::BusinessType.find_or_create_by!(name: "Wholesale Distributor")
38
- retail_type = Dscf::Core::BusinessType.find_or_create_by!(name: "Retail Store")
39
-
40
- # Consumers
41
- consumer1 = Dscf::Core::User.create!(
42
- email: "abebe.consumer@example.com",
43
- phone: "+251911123456"
44
- )
45
- consumer2 = Dscf::Core::User.create!(
46
- email: "tigist.consumer@example.com",
47
- phone: "+251922334567"
48
- )
49
-
50
- # Drivers
51
- driver1 = Dscf::Core::User.create!(
52
- email: "driver.ahmed@example.com",
53
- phone: "+251933445678"
54
- )
55
- Dscf::Core::User.create!(
56
- email: "driver.mariam@example.com",
57
- phone: "+251944556789"
58
- )
59
-
60
- puts "✅ Created #{Dscf::Core::User.count} users (#{Dscf::Core::User.where("email LIKE ?", "%consumer%").count} consumers, #{Dscf::Core::User.where("email LIKE ?", "%driver%").count} drivers)"
61
-
62
- puts "🏢 Creating businesses and linking to users..."
63
-
64
- # Wholesalers
65
- wholesale_user1 = Dscf::Core::User.create!(
66
- email: "wholesale.addis@example.com",
67
- phone: "+251955667890"
68
- )
69
- wholesaler1 = Dscf::Core::Business.create!(
70
- name: "Addis Wholesale Distributors",
71
- contact_email: "contact@addiswholesale.et",
72
- contact_phone: "+251966778901",
73
- tin_number: "1234567890",
74
- business_type: wholesale_type,
75
- user: wholesale_user1
76
- )
77
-
78
- wholesale_user2 = Dscf::Core::User.create!(
79
- email: "wholesale.ethio@example.com",
80
- phone: "+251977889012"
81
- )
82
- wholesaler2 = Dscf::Core::Business.create!(
83
- name: "Ethio Agricultural Wholesale",
84
- contact_email: "info@ethiowholesale.et",
85
- contact_phone: "+251988990123",
86
- tin_number: "0987654321",
87
- business_type: wholesale_type,
88
- user: wholesale_user2
89
- )
90
-
91
- # Retailers
92
- retail_user1 = Dscf::Core::User.create!(
93
- email: "retail.meklit@example.com",
94
- phone: "+251999001234"
95
- )
96
- Dscf::Core::Business.create!(
97
- name: "Meklit Fresh Market",
98
- contact_email: "meklit@freshmarket.et",
99
- contact_phone: "+251910112345",
100
- tin_number: "1122334455",
101
- business_type: retail_type,
102
- user: retail_user1
103
- )
104
-
105
- retail_user2 = Dscf::Core::User.create!(
106
- email: "retail.bole@example.com",
107
- phone: "+251921223456"
108
- )
109
- Dscf::Core::Business.create!(
110
- name: "Bole Modern Supermarket",
111
- contact_email: "info@bolesuper.et",
112
- contact_phone: "+251932334567",
113
- tin_number: "5566778899",
114
- business_type: retail_type,
115
- user: retail_user2
116
- )
117
-
118
- puts "✅ Created #{Dscf::Core::Business.count} businesses (#{Dscf::Core::Business.joins(:user).where("dscf_core_users.email LIKE ?", "%wholesale%").count} wholesalers, #{Dscf::Core::Business.joins(:user).where("dscf_core_users.email LIKE ?", "%retail%").count} retailers)"
119
-
120
- puts "📦 Creating products and supplier listings..."
121
-
122
- # Products from wholesalers
123
- banana_product = wholesaler1.supplier_products.create!(
124
- product: Dscf::Marketplace::Product.create!(
125
- name: "Fresh Bananas",
126
- category: fruits_veg,
127
- unit: kg
128
- )
129
- )
130
- banana_listing = Dscf::Marketplace::Listing.create!(
131
- supplier_product: banana_product,
132
- price: 25.00,
133
- quantity: 1000,
134
- status: :active
135
- )
136
-
137
- milk_product = wholesaler2.supplier_products.create!(
138
- product: Dscf::Marketplace::Product.create!(
139
- name: "Fresh Cow Milk",
140
- category: dairy,
141
- unit: liter
142
- )
143
- )
144
- milk_listing = Dscf::Marketplace::Listing.create!(
145
- supplier_product: milk_product,
146
- price: 45.00,
147
- quantity: 500,
148
- status: :active
149
- )
150
-
151
- puts "✅ Created #{Dscf::Marketplace::Product.count} products and #{Dscf::Marketplace::Listing.count} active listings"
152
-
153
- puts "📋 Creating RFQs and quotations..."
154
-
155
- # RFQ from retailer to wholesalers
156
- rfq = Dscf::Marketplace::RequestForQuotation.create!(
157
- user: retail_user1,
158
- status: :sent,
159
- notes: "Monthly supply of fresh produce"
160
- )
161
-
162
- # RFQ items
163
- rfq.rfq_items.create!(
164
- product: banana_product.product,
165
- unit: kg,
166
- quantity: 200,
167
- notes: "Premium quality bananas"
168
- )
169
-
170
- rfq.rfq_items.create!(
171
- product: milk_product.product,
172
- unit: liter,
173
- quantity: 100,
174
- notes: "Fresh morning milk"
175
- )
176
-
177
- # Quotations from wholesalers
178
- quotation1 = Dscf::Marketplace::Quotation.create!(
179
- request_for_quotation: rfq,
180
- business: wholesaler1,
181
- total_price: 5000.00,
182
- delivery_date: 3.days.from_now.to_date,
183
- valid_until: 10.days.from_now,
184
- status: :accepted,
185
- notes: "Competitive pricing for bulk orders"
186
- )
187
-
188
- quotation1.quotation_items.create!(
189
- rfq_item: rfq.rfq_items.first,
190
- product: banana_product.product,
191
- unit: kg,
192
- quantity: 200,
193
- unit_price: 25.00
194
- )
195
-
196
- quotation2 = Dscf::Marketplace::Quotation.create!(
197
- request_for_quotation: rfq,
198
- business: wholesaler2,
199
- total_price: 4500.00,
200
- delivery_date: 2.days.from_now.to_date,
201
- valid_until: 8.days.from_now,
202
- status: :sent,
203
- notes: "Direct from farm fresh milk"
204
- )
205
-
206
- quotation2.quotation_items.create!(
207
- rfq_item: rfq.rfq_items.second,
208
- product: milk_product.product,
209
- unit: liter,
210
- quantity: 100,
211
- unit_price: 45.00
212
- )
213
-
214
- puts "✅ Created #{Dscf::Marketplace::RequestForQuotation.count} RFQs with #{Dscf::Marketplace::Quotation.count} quotations"
215
-
216
- puts "🛒 Creating orders from consumers and retailers..."
217
-
218
- # Addresses for orders
219
- consumer_address = Dscf::Core::Address.create!(
220
- user: consumer1,
221
- address_type: :shipping,
222
- country: "Ethiopia",
223
- city: "Addis Ababa",
224
- sub_city: "Bole",
225
- woreda: "05",
226
- kebele: "09",
227
- house_numbers: "123",
228
- po_box: "5678",
229
- latitude: 9.0108,
230
- longitude: 38.7613
231
- )
232
-
233
- retailer_address = Dscf::Core::Address.create!(
234
- user: retail_user1,
235
- address_type: :shipping,
236
- country: "Ethiopia",
237
- city: "Addis Ababa",
238
- sub_city: "Piassa",
239
- woreda: "01",
240
- kebele: "12",
241
- house_numbers: "456",
242
- po_box: "9012",
243
- latitude: 9.0308,
244
- longitude: 38.7413
245
- )
246
-
247
- # Order from consumer via direct listing
248
- consumer_order = Dscf::Marketplace::Order.create_from_listing(
249
- milk_listing,
250
- consumer1,
251
- 10,
252
- consumer_address
253
- )
254
-
255
- # Order from retailer via accepted quotation
256
- retailer_order = Dscf::Marketplace::Order.create_from_quotation(
257
- quotation1,
258
- retailer_address
259
- )
260
-
261
- puts "✅ Created #{Dscf::Marketplace::Order.count} orders (#{Dscf::Marketplace::Order.where(order_type: :direct_listing).count} direct, #{Dscf::Marketplace::Order.where(order_type: :rfq_based).count} RFQ-based)"
262
-
263
- puts "🚚 Creating delivery orders with multiple dropoffs..."
264
-
265
- # Pickup address
266
- pickup_address = Dscf::Core::Address.create!(
267
- user: wholesaler1.user,
268
- address_type: :business,
269
- country: "Ethiopia",
270
- city: "Addis Ababa",
271
- sub_city: "Kazanchis",
272
- woreda: "03",
273
- kebele: "15",
274
- house_numbers: "789",
275
- po_box: "3456",
276
- latitude: 9.0208,
277
- longitude: 38.7513
278
- )
279
-
280
- # Additional dropoff
281
- extra_address = Dscf::Core::Address.create!(
282
- user: consumer2,
283
- address_type: :shipping,
284
- country: "Ethiopia",
285
- city: "Addis Ababa",
286
- sub_city: "Merkato",
287
- woreda: "07",
288
- kebele: "21",
289
- house_numbers: "101",
290
- po_box: "7890",
291
- latitude: 9.0008,
292
- longitude: 38.7713
293
- )
294
-
295
- # Create delivery order
296
- delivery_order = Dscf::Marketplace::DeliveryOrder.create!(
297
- driver: driver1,
298
- pickup_address: pickup_address,
299
- status: :assigned,
300
- vehicle_type: :motorcycle,
301
- estimated_delivery_price: 150.00,
302
- estimated_delivery_time: 2.hours.from_now
303
- )
304
-
305
- # Associate orders
306
- consumer_order.update!(delivery_order: delivery_order)
307
- retailer_order.update!(delivery_order: delivery_order)
308
-
309
- # Create additional order for third dropoff
310
- extra_order = Dscf::Marketplace::Order.create_from_listing(
311
- banana_listing,
312
- consumer2,
313
- 5,
314
- extra_address
315
- )
316
- extra_order.update!(delivery_order: delivery_order)
317
-
318
- # Create delivery order items
319
- delivery_order.delivery_order_items.create!(
320
- order_item: consumer_order.order_items.first,
321
- pickup_address: pickup_address,
322
- dropoff_address: consumer_address
323
- )
1
+ puts "🌱 Seeding marketplace permissions and default USER role..."
2
+
3
+ Dscf::Core::PermissionRegistry.register("dscf-marketplace") do
4
+ resource :categories, actions: %i[index show create update destroy subcategories]
5
+ resource :products, actions: %i[index show create update destroy filter supplier_products]
6
+ resource :units, actions: %i[index show create update destroy]
7
+ resource :unit_conversions, actions: %i[index show create update destroy]
8
+ resource :supplier_products, actions: %i[index show create update destroy my_products]
9
+ resource :listings, actions: %i[index show create update destroy activate pause sold_out my_listings listings_by_supplier]
10
+ resource :request_for_quotations, actions: %i[index show create update destroy send_rfq close respond my_rfqs filter]
11
+ resource :rfq_items, actions: %i[index show create update destroy]
12
+ resource :quotations, actions: %i[index show create update destroy accept reject send_quotation my_quotes filter]
13
+ resource :quotation_items, actions: %i[index show create update destroy]
14
+ resource :orders, actions: %i[index show create update destroy confirm cancel complete my_orders filter]
15
+ resource :order_items, actions: %i[index show create update destroy]
16
+ resource :delivery_orders, actions: %i[
17
+ index show create update destroy pickup start_delivery complete_delivery mark_failed accept summary
18
+ my_driver_deliveries filter convert_orders
19
+ ]
20
+ resource :delivery_stops, actions: %i[index show create update destroy verify]
21
+ resource :delivery_order_items, actions: %i[index show create update destroy receiver_confirm report_issue dispute_delivery]
22
+ resource :delivery_vehicles, actions: %i[index show create update destroy]
23
+ resource :locations, actions: %i[get_location]
24
+ end
324
25
 
325
- delivery_order.delivery_order_items.create!(
326
- order_item: retailer_order.order_items.first,
327
- pickup_address: pickup_address,
328
- dropoff_address: retailer_address
329
- )
26
+ user_role = Dscf::Core::Role.find_or_create_by!(code: "USER") do |role|
27
+ role.name = "User"
28
+ role.active = true
29
+ end
30
+ user_role.update!(name: "User", active: true)
330
31
 
331
- delivery_order.delivery_order_items.create!(
332
- order_item: extra_order.order_items.first,
333
- pickup_address: pickup_address,
334
- dropoff_address: extra_address
335
- )
32
+ marketplace_permissions = Dscf::Core::Permission.where(engine: "dscf-marketplace")
336
33
 
337
- puts "✅ Created #{Dscf::Marketplace::DeliveryOrder.count} delivery orders with #{Dscf::Marketplace::DeliveryOrderItem.count} total dropoffs"
338
- puts "🎉 Demo seed completed! Created realistic supply chain with #{Dscf::Core::User.count} users, #{Dscf::Core::Business.count} businesses, and #{Dscf::Marketplace::Order.count} orders across the platform."
339
- rescue => e
340
- puts "❌ Seed failed: #{e.message}"
341
- puts e.backtrace
342
- raise
34
+ marketplace_permissions.find_each do |permission|
35
+ Dscf::Core::RolePermission.find_or_create_by!(role: user_role, permission: permission)
343
36
  end
37
+
38
+ puts "✅ Seeded #{marketplace_permissions.count} marketplace permissions and assigned to USER role."
@@ -1,5 +1,5 @@
1
1
  module Dscf
2
2
  module Marketplace
3
- VERSION = "0.7.0".freeze
3
+ VERSION = "0.7.2".freeze
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dscf-marketplace
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.7.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Asrat
@@ -453,6 +453,23 @@ files:
453
453
  - app/models/dscf/marketplace/supplier_product.rb
454
454
  - app/models/dscf/marketplace/unit.rb
455
455
  - app/models/dscf/marketplace/unit_conversion.rb
456
+ - app/policies/dscf/marketplace/category_policy.rb
457
+ - app/policies/dscf/marketplace/delivery_order_item_policy.rb
458
+ - app/policies/dscf/marketplace/delivery_order_policy.rb
459
+ - app/policies/dscf/marketplace/delivery_stop_policy.rb
460
+ - app/policies/dscf/marketplace/delivery_vehicle_policy.rb
461
+ - app/policies/dscf/marketplace/listing_policy.rb
462
+ - app/policies/dscf/marketplace/location_policy.rb
463
+ - app/policies/dscf/marketplace/order_item_policy.rb
464
+ - app/policies/dscf/marketplace/order_policy.rb
465
+ - app/policies/dscf/marketplace/product_policy.rb
466
+ - app/policies/dscf/marketplace/quotation_item_policy.rb
467
+ - app/policies/dscf/marketplace/quotation_policy.rb
468
+ - app/policies/dscf/marketplace/request_for_quotation_policy.rb
469
+ - app/policies/dscf/marketplace/rfq_item_policy.rb
470
+ - app/policies/dscf/marketplace/supplier_product_policy.rb
471
+ - app/policies/dscf/marketplace/unit_conversion_policy.rb
472
+ - app/policies/dscf/marketplace/unit_policy.rb
456
473
  - app/serializers/dscf/marketplace/category_serializer.rb
457
474
  - app/serializers/dscf/marketplace/delivery_order_item_serializer.rb
458
475
  - app/serializers/dscf/marketplace/delivery_order_serializer.rb
@@ -512,6 +529,8 @@ files:
512
529
  - db/migrate/20251006055948_change_default_payment_method_on_orders.rb
513
530
  - db/migrate/20251130143731_create_dscf_marketplace_delivery_stops.rb
514
531
  - db/migrate/20251130144500_add_delivery_stop_to_delivery_order_items.rb
532
+ - db/migrate/20260310120000_add_active_and_description_to_dscf_core_roles.rb
533
+ - db/migrate/20260310122000_add_missing_fields_to_dscf_core_user_roles.rb
515
534
  - db/seeds.rb
516
535
  - lib/dscf/marketplace.rb
517
536
  - lib/dscf/marketplace/engine.rb