dscf-marketplace 0.1.9 → 0.2.1

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 (29) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/dscf/marketplace/businesses_controller.rb +34 -0
  3. data/app/controllers/dscf/marketplace/delivery_order_items_controller.rb +64 -0
  4. data/app/controllers/dscf/marketplace/delivery_orders_controller.rb +72 -0
  5. data/app/controllers/dscf/marketplace/delivery_vehicles_controller.rb +28 -0
  6. data/app/controllers/dscf/marketplace/order_items_controller.rb +29 -0
  7. data/app/controllers/dscf/marketplace/quotation_items_controller.rb +28 -0
  8. data/app/controllers/dscf/marketplace/rfq_items_controller.rb +28 -0
  9. data/app/controllers/dscf/marketplace/supplier_products_controller.rb +29 -0
  10. data/app/controllers/dscf/marketplace/unit_conversions_controller.rb +28 -0
  11. data/app/controllers/dscf/marketplace/units_controller.rb +26 -0
  12. data/app/models/dscf/marketplace/delivery_order.rb +6 -0
  13. data/app/models/dscf/marketplace/quotation_item.rb +42 -10
  14. data/app/serializers/dscf/marketplace/business_serializer.rb +11 -0
  15. data/app/serializers/dscf/marketplace/delivery_order_item_serializer.rb +17 -0
  16. data/app/serializers/dscf/marketplace/delivery_order_serializer.rb +17 -0
  17. data/app/serializers/dscf/marketplace/delivery_vehicle_serializer.rb +12 -0
  18. data/app/serializers/dscf/marketplace/order_item_serializer.rb +16 -0
  19. data/app/serializers/dscf/marketplace/quotation_item_serializer.rb +16 -0
  20. data/app/serializers/dscf/marketplace/rfq_item_serializer.rb +14 -0
  21. data/app/serializers/dscf/marketplace/supplier_product_serializer.rb +13 -0
  22. data/app/serializers/dscf/marketplace/unit_conversion_serializer.rb +11 -0
  23. data/app/serializers/dscf/marketplace/unit_serializer.rb +9 -0
  24. data/config/locales/en.yml +12 -0
  25. data/config/routes.rb +10 -4
  26. data/lib/dscf/marketplace/version.rb +1 -1
  27. data/spec/factories/dscf/marketplace/delivery_order_items.rb +1 -1
  28. data/spec/factories/dscf/marketplace/quotation_items.rb +2 -2
  29. metadata +22 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e5af5705a5f167b0e7f9f34ae086a62f92528d0634e53ca1b50e1ddd0894934b
4
- data.tar.gz: c53e6675625b7a1225ed8cdaaf977e940325ff9d9fe934f84a47517b22b82302
3
+ metadata.gz: 70190000bbbdf144579c8e6c27608664b18a4a8460ac43350f9dc1162c355b0a
4
+ data.tar.gz: 1e661035af4d825af27418bf07a7342eaa641d39ea6e20fd1cc62dd64aecbd75
5
5
  SHA512:
6
- metadata.gz: 69d7b1dc54ca8c0df0177243a8a9c2b9e410348b7aaf53464890c07f90c2e13a0c9313805992db5e7f80962c771cde51ab7889046fb93a7ad7c4d07c532880ad
7
- data.tar.gz: c00490bed736cc44c717edc3cbb64de8f2ebac369fd6f1ec98ecf24f44d4c00d07b52aeda5062d04663ecd079948890d0fe160721c2f2295272790b588bde568
6
+ metadata.gz: 1a1fb37f55cd3d15a6a89098f435dd8f7797748440dff0f68aac15be45a92c1e3b7807ef2307013846cdab795153a8b956fdc50eaa569424a9ec88695f77763e
7
+ data.tar.gz: a18369805514a3d9d24562ada719551baf8e06621a5bb5b806afafd900f8245dbdc16568f6514ec77953055c6faece98fa937961ba05a28d9c8aaed853393828
@@ -0,0 +1,34 @@
1
+ module Dscf
2
+ module Marketplace
3
+ class BusinessesController < ApplicationController
4
+ include Dscf::Core::Common
5
+
6
+ def has_business
7
+ has_business = current_user&.businesses&.exists? || false
8
+ render_success("business.success.has_business_check", data: {has_business: has_business})
9
+ end
10
+
11
+ private
12
+
13
+ def model_params
14
+ params.require(:business).permit(
15
+ :name, :description, :contact_email, :contact_phone, :tin_number,
16
+ :business_type_id, :user_id
17
+ )
18
+ end
19
+
20
+ def eager_loaded_associations
21
+ [ :business_type, :user ]
22
+ end
23
+
24
+ def default_serializer_includes
25
+ {
26
+ index: [ :business_type, :user ],
27
+ show: [ :business_type, :user ],
28
+ create: [ :business_type, :user ],
29
+ update: [ :business_type, :user ]
30
+ }
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,64 @@
1
+ module Dscf
2
+ module Marketplace
3
+ class DeliveryOrderItemsController < ApplicationController
4
+ include Dscf::Core::Common
5
+
6
+ def receiver_confirm
7
+ @obj = find_record
8
+ if @obj.receiver_confirm!(params[:confirmed_quantity], params[:notes], current_user&.id)
9
+ render_success("delivery_order_items.success.receiver_confirmed", data: @obj)
10
+ else
11
+ render_error("delivery_order_items.errors.receiver_confirm_failed")
12
+ end
13
+ end
14
+
15
+ def report_issue
16
+ @obj = find_record
17
+ issue_type = params[:issue_type]
18
+ quantity = params[:quantity]
19
+ description = params[:description]
20
+
21
+ if @obj.report_issue!(issue_type, quantity, description, current_user&.id)
22
+ render_success("delivery_order_items.success.issue_reported", data: @obj)
23
+ else
24
+ render_error("delivery_order_items.errors.report_issue_failed")
25
+ end
26
+ end
27
+
28
+ def dispute_delivery
29
+ @obj = find_record
30
+ reason = params[:reason]
31
+
32
+ if @obj.dispute_delivery!(reason, current_user&.id)
33
+ render_success("delivery_order_items.success.delivery_disputed", data: @obj)
34
+ else
35
+ render_error("delivery_order_items.errors.dispute_delivery_failed")
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def model_params
42
+ params.require(:delivery_order_item).permit(
43
+ :delivery_order_id, :order_item_id, :pickup_address_id, :dropoff_address_id,
44
+ :quantity, :status, :pickup_verified_quantity, :dropoff_verified_quantity,
45
+ :damaged_quantity, :missing_quantity, :receiver_confirmed_by,
46
+ :receiver_confirmed_at, :receiver_notes, :handoff_checklist_completed
47
+ )
48
+ end
49
+
50
+ def eager_loaded_associations
51
+ [ :delivery_order, :order_item, :pickup_address, :dropoff_address ]
52
+ end
53
+
54
+ def default_serializer_includes
55
+ {
56
+ index: [ :delivery_order, :order_item ],
57
+ show: [ :delivery_order, :order_item, :pickup_address, :dropoff_address ],
58
+ create: [ :delivery_order, :order_item ],
59
+ update: [ :delivery_order, :order_item ]
60
+ }
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,72 @@
1
+ module Dscf
2
+ module Marketplace
3
+ class DeliveryOrdersController < ApplicationController
4
+ include Dscf::Core::Common
5
+
6
+ def index
7
+ @objs = DeliveryOrder.all
8
+ render_success("delivery_orders.index.success", data: @objs, serializer_options: {include: default_serializer_includes[:index]})
9
+ end
10
+
11
+ def pickup
12
+ @obj = find_record
13
+ if @obj.pickup!
14
+ render_success("delivery_orders.success.picked_up", data: @obj)
15
+ else
16
+ render_error("delivery_orders.errors.pickup_failed")
17
+ end
18
+ end
19
+
20
+ def start_delivery
21
+ @obj = find_record
22
+ if @obj.start_delivery!
23
+ render_success("delivery_orders.success.delivery_started", data: @obj)
24
+ else
25
+ render_error("delivery_orders.errors.start_delivery_failed")
26
+ end
27
+ end
28
+
29
+ def complete_delivery
30
+ @obj = find_record
31
+ if @obj.complete_delivery!
32
+ render_success("delivery_orders.success.delivery_completed", data: @obj)
33
+ else
34
+ render_error("delivery_orders.errors.complete_delivery_failed")
35
+ end
36
+ end
37
+
38
+ def mark_failed
39
+ @obj = find_record
40
+ reason = params[:reason]
41
+ if @obj.mark_failed!(reason)
42
+ render_success("delivery_orders.success.marked_failed", data: @obj)
43
+ else
44
+ render_error("delivery_orders.errors.mark_failed_failed")
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ def model_params
51
+ params.require(:delivery_order).permit(
52
+ :driver_id, :pickup_address_id, :delivery_vehicle_id, :status,
53
+ :vehicle_type, :estimated_delivery_price, :actual_delivery_price,
54
+ :estimated_delivery_time, :actual_delivery_time, :delivery_notes
55
+ )
56
+ end
57
+
58
+ def eager_loaded_associations
59
+ [ :driver, :pickup_address, :delivery_vehicle, :delivery_order_items, :marketplace_orders ]
60
+ end
61
+
62
+ def default_serializer_includes
63
+ {
64
+ index: [ :driver, :pickup_address, :delivery_vehicle ],
65
+ show: [ :driver, :pickup_address, :delivery_vehicle, :delivery_order_items, :marketplace_orders ],
66
+ create: [ :driver, :pickup_address, :delivery_vehicle ],
67
+ update: [ :driver, :pickup_address, :delivery_vehicle ]
68
+ }
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,28 @@
1
+ module Dscf
2
+ module Marketplace
3
+ class DeliveryVehiclesController < ApplicationController
4
+ include Dscf::Core::Common
5
+
6
+ private
7
+
8
+ def model_params
9
+ params.require(:delivery_vehicle).permit(
10
+ :driver_id, :plate_number, :vehicle_type, :year, :brand, :model, :color
11
+ )
12
+ end
13
+
14
+ def eager_loaded_associations
15
+ [ :driver, :delivery_orders ]
16
+ end
17
+
18
+ def default_serializer_includes
19
+ {
20
+ index: [ :driver ],
21
+ show: [ :driver, :delivery_orders ],
22
+ create: [ :driver ],
23
+ update: [ :driver ]
24
+ }
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,29 @@
1
+ module Dscf
2
+ module Marketplace
3
+ class OrderItemsController < ApplicationController
4
+ include Dscf::Core::Common
5
+
6
+ private
7
+
8
+ def model_params
9
+ params.require(:order_item).permit(
10
+ :order_id, :quotation_item_id, :listing_id,
11
+ :product_id, :unit_id, :quantity, :unit_price, :status
12
+ )
13
+ end
14
+
15
+ def eager_loaded_associations
16
+ [ :order, :quotation_item, :listing, :product, :unit ]
17
+ end
18
+
19
+ def default_serializer_includes
20
+ {
21
+ index: [ :product, :unit ],
22
+ show: [ :order, :quotation_item, :listing, :product, :unit ],
23
+ create: [ :product, :unit ],
24
+ update: [ :product, :unit ]
25
+ }
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,28 @@
1
+ module Dscf
2
+ module Marketplace
3
+ class QuotationItemsController < ApplicationController
4
+ include Dscf::Core::Common
5
+
6
+ private
7
+
8
+ def model_params
9
+ params.require(:quotation_item).permit(
10
+ :quotation_id, :rfq_item_id, :product_id, :unit_id, :quantity, :unit_price
11
+ )
12
+ end
13
+
14
+ def eager_loaded_associations
15
+ [ :quotation, :rfq_item, :product, :unit ]
16
+ end
17
+
18
+ def default_serializer_includes
19
+ {
20
+ index: [ :quotation, :rfq_item, :product, :unit ],
21
+ show: [ :quotation, :rfq_item, :product, :unit ],
22
+ create: [ :quotation, :rfq_item, :product, :unit ],
23
+ update: [ :quotation, :rfq_item, :product, :unit ]
24
+ }
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,28 @@
1
+ module Dscf
2
+ module Marketplace
3
+ class RfqItemsController < ApplicationController
4
+ include Dscf::Core::Common
5
+
6
+ private
7
+
8
+ def model_params
9
+ params.require(:rfq_item).permit(
10
+ :request_for_quotation_id, :product_id, :unit_id, :quantity, :notes
11
+ )
12
+ end
13
+
14
+ def eager_loaded_associations
15
+ [ :request_for_quotation, :product, :unit, :quotation_items ]
16
+ end
17
+
18
+ def default_serializer_includes
19
+ {
20
+ index: [ :request_for_quotation, :product, :unit ],
21
+ show: [ :request_for_quotation, :product, :unit, :quotation_items ],
22
+ create: [ :request_for_quotation, :product, :unit ],
23
+ update: [ :request_for_quotation, :product, :unit ]
24
+ }
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,29 @@
1
+ module Dscf
2
+ module Marketplace
3
+ class SupplierProductsController < ApplicationController
4
+ include Dscf::Core::Common
5
+
6
+ private
7
+
8
+ def model_params
9
+ params.require(:supplier_product).permit(
10
+ :business_id, :product_id, :supplier_price, :available_quantity,
11
+ :minimum_order_quantity, :status
12
+ )
13
+ end
14
+
15
+ def eager_loaded_associations
16
+ [ :business, :product, :listings ]
17
+ end
18
+
19
+ def default_serializer_includes
20
+ {
21
+ index: [ :business, :product ],
22
+ show: [ :business, :product, :listings ],
23
+ create: [ :business, :product ],
24
+ update: [ :business, :product ]
25
+ }
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,28 @@
1
+ module Dscf
2
+ module Marketplace
3
+ class UnitConversionsController < ApplicationController
4
+ include Dscf::Core::Common
5
+
6
+ private
7
+
8
+ def model_params
9
+ params.require(:unit_conversion).permit(
10
+ :from_unit_id, :to_unit_id, :conversion_factor, :notes
11
+ )
12
+ end
13
+
14
+ def eager_loaded_associations
15
+ [ :from_unit, :to_unit ]
16
+ end
17
+
18
+ def default_serializer_includes
19
+ {
20
+ index: [ :from_unit, :to_unit ],
21
+ show: [ :from_unit, :to_unit ],
22
+ create: [ :from_unit, :to_unit ],
23
+ update: [ :from_unit, :to_unit ]
24
+ }
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,26 @@
1
+ module Dscf
2
+ module Marketplace
3
+ class UnitsController < ApplicationController
4
+ include Dscf::Core::Common
5
+
6
+ private
7
+
8
+ def model_params
9
+ params.require(:unit).permit(:code, :name, :unit_type)
10
+ end
11
+
12
+ def eager_loaded_associations
13
+ [ :unit_conversions ]
14
+ end
15
+
16
+ def default_serializer_includes
17
+ {
18
+ index: [ :unit_conversions ],
19
+ show: [ :unit_conversions ],
20
+ create: [],
21
+ update: []
22
+ }
23
+ end
24
+ end
25
+ end
26
+ end
@@ -23,6 +23,12 @@ module Dscf::Marketplace
23
23
  %w[id driver_id pickup_address_id delivery_vehicle_id status vehicle_type estimated_delivery_price actual_delivery_price estimated_delivery_time actual_delivery_time delivery_notes created_at updated_at]
24
24
  end
25
25
 
26
+ # Override ransack to handle JSON fields
27
+ def self.ransack(params = {}, options = {})
28
+ params ||= {}
29
+ super(params.except("optimized_route"), options)
30
+ end
31
+
26
32
  def self.ransackable_associations(_auth_object = nil)
27
33
  %w[driver pickup_address delivery_vehicle delivery_order_items marketplace_orders]
28
34
  end
@@ -13,13 +13,10 @@ module Dscf
13
13
  validates :unit_id, presence: true
14
14
  validates :unit_price, numericality: {greater_than: 0}, allow_nil: true
15
15
  validates :subtotal, numericality: {greater_than_or_equal_to: 0}, allow_nil: true
16
-
17
16
  validate :product_matches_rfq_item
18
17
  validate :unit_compatible_with_product
19
- before_save :calculate_subtotal, if: :unit_price_changed?
20
-
21
- # Only validate subtotal calculation if both unit_price and quantity are present
22
18
  validate :subtotal_matches_calculation, if: :should_validate_subtotal?
19
+ before_save :calculate_subtotal, if: :should_recalculate_subtotal?
23
20
 
24
21
  scope :priced, -> { where.not(unit_price: nil) }
25
22
  scope :unpriced, -> { where(unit_price: nil) }
@@ -76,8 +73,7 @@ module Dscf
76
73
  def matches_rfq_request?
77
74
  return false unless rfq_item
78
75
 
79
- product_id == rfq_item.product_id &&
80
- unit_id == rfq_item.unit_id
76
+ product_id == rfq_item.product_id && unit_id == rfq_item.unit_id
81
77
  end
82
78
 
83
79
  def can_create_order?
@@ -89,8 +85,35 @@ module Dscf
89
85
  def calculate_subtotal
90
86
  return unless unit_price && quantity
91
87
 
92
- self.subtotal = unit_price * quantity
88
+ self.subtotal = (unit_price * quantity).round(2)
89
+ end
90
+
91
+ # Calculate subtotal automatically if not set
92
+ def calculated_subtotal
93
+ return subtotal if subtotal.present?
94
+ return nil unless unit_price && quantity
95
+
96
+ (unit_price * quantity).round(2)
97
+ end
98
+
99
+ # Override subtotal setter to allow validation to work
100
+ def subtotal=(value)
101
+ # Allow any value to be set for validation purposes
102
+ super
93
103
  end
104
+ public :subtotal=
105
+
106
+ # Override subtotal getter to calculate if not set
107
+ def subtotal
108
+ stored_value = super
109
+ # If we have a stored value (including 0), return it
110
+ # Only calculate if it's nil and we have the required fields
111
+ return stored_value unless stored_value.nil?
112
+ return nil unless unit_price && quantity
113
+
114
+ (unit_price * quantity).round(2)
115
+ end
116
+ public :subtotal
94
117
 
95
118
  def product_matches_rfq_item
96
119
  return unless rfq_item_id && product_id
@@ -111,14 +134,23 @@ module Dscf
111
134
  def subtotal_matches_calculation
112
135
  return unless should_validate_subtotal?
113
136
 
114
- expected_subtotal = unit_price * quantity
115
- unless subtotal == expected_subtotal
137
+ # Calculate what the subtotal should be based on current unit_price and quantity
138
+ expected_subtotal = (unit_price * quantity).round(2)
139
+
140
+ # If subtotal is stored and doesn't match, that's an error
141
+ # If subtotal is nil, we'll let the before_save callback handle it
142
+ if subtotal.present? && subtotal.round(2) != expected_subtotal
116
143
  errors.add(:subtotal, "must equal unit_price * quantity")
117
144
  end
118
145
  end
119
146
 
120
147
  def should_validate_subtotal?
121
- unit_price.present? && quantity.present? && subtotal.present?
148
+ # Only validate if subtotal is explicitly set and we have unit_price and quantity
149
+ unit_price.present? && quantity.present? && subtotal.present? && subtotal_changed?
150
+ end
151
+
152
+ def should_recalculate_subtotal?
153
+ unit_price_changed? || quantity_changed?
122
154
  end
123
155
  end
124
156
  end
@@ -0,0 +1,11 @@
1
+ module Dscf
2
+ module Marketplace
3
+ class BusinessSerializer < ActiveModel::Serializer
4
+ attributes :id, :name, :description, :contact_email, :contact_phone,
5
+ :tin_number, :created_at, :updated_at
6
+
7
+ belongs_to :business_type
8
+ belongs_to :user
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,17 @@
1
+ module Dscf
2
+ module Marketplace
3
+ class DeliveryOrderItemSerializer < ActiveModel::Serializer
4
+ attributes :id, :delivery_order_id, :order_item_id, :pickup_address_id, :dropoff_address_id,
5
+ :quantity, :status, :pickup_verified_quantity, :dropoff_verified_quantity,
6
+ :damaged_quantity, :missing_quantity, :receiver_confirmed_by,
7
+ :receiver_confirmed_at, :receiver_notes, :handoff_checklist_completed,
8
+ :created_at, :updated_at, :product_name, :unit_name, :verification_complete?,
9
+ :has_discrepancy?, :discrepancy_amount, :requires_resolution?
10
+
11
+ belongs_to :delivery_order
12
+ belongs_to :order_item
13
+ belongs_to :pickup_address
14
+ belongs_to :dropoff_address
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Dscf
2
+ module Marketplace
3
+ class DeliveryOrderSerializer < ActiveModel::Serializer
4
+ attributes :id, :driver_id, :pickup_address_id, :delivery_vehicle_id, :status,
5
+ :vehicle_type, :estimated_delivery_price, :actual_delivery_price,
6
+ :estimated_delivery_time, :actual_delivery_time, :delivery_notes,
7
+ :created_at, :updated_at, :total_items, :total_orders, :delivery_duration,
8
+ :on_time?, :all_handoffs_confirmed?
9
+
10
+ belongs_to :driver
11
+ belongs_to :pickup_address
12
+ belongs_to :delivery_vehicle
13
+ has_many :delivery_order_items
14
+ has_many :marketplace_orders
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,12 @@
1
+ module Dscf
2
+ module Marketplace
3
+ class DeliveryVehicleSerializer < ActiveModel::Serializer
4
+ attributes :id, :driver_id, :plate_number, :vehicle_type, :year, :brand,
5
+ :model, :color, :created_at, :updated_at, :display_name,
6
+ :total_deliveries, :success_rate
7
+
8
+ belongs_to :driver
9
+ has_many :delivery_orders
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,16 @@
1
+ module Dscf
2
+ module Marketplace
3
+ class OrderItemSerializer < ActiveModel::Serializer
4
+ attributes :id, :order_id, :quotation_item_id, :listing_id,
5
+ :product_id, :unit_id, :quantity, :unit_price,
6
+ :status, :created_at, :updated_at,
7
+ :subtotal, :product_name, :unit_name
8
+
9
+ belongs_to :order
10
+ belongs_to :quotation_item
11
+ belongs_to :listing
12
+ belongs_to :product
13
+ belongs_to :unit
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ module Dscf
2
+ module Marketplace
3
+ class QuotationItemSerializer < ActiveModel::Serializer
4
+ attributes :id, :quotation_id, :rfq_item_id, :product_id, :unit_id, :quantity,
5
+ :unit_price, :subtotal, :created_at, :updated_at, :product_name,
6
+ :product_sku, :unit_name, :unit_code, :rfq_requested_quantity,
7
+ :quantity_difference, :quantity_difference_percentage, :price_per_base_unit,
8
+ :matches_rfq_request?, :can_create_order?
9
+
10
+ belongs_to :quotation
11
+ belongs_to :rfq_item
12
+ belongs_to :product
13
+ belongs_to :unit
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,14 @@
1
+ module Dscf
2
+ module Marketplace
3
+ class RfqItemSerializer < ActiveModel::Serializer
4
+ attributes :id, :request_for_quotation_id, :product_id, :unit_id, :quantity, :notes,
5
+ :created_at, :updated_at, :product_name, :product_sku, :unit_name,
6
+ :unit_code, :quotation_count, :has_quotations?, :quoted_price_range
7
+
8
+ belongs_to :request_for_quotation
9
+ belongs_to :product
10
+ belongs_to :unit
11
+ has_many :quotation_items
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ module Dscf
2
+ module Marketplace
3
+ class SupplierProductSerializer < ActiveModel::Serializer
4
+ attributes :id, :business_id, :product_id, :supplier_price, :available_quantity,
5
+ :minimum_order_quantity, :status, :created_at, :updated_at,
6
+ :in_stock?, :price_per_unit, :display_name
7
+
8
+ belongs_to :business
9
+ belongs_to :product
10
+ has_many :listings
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ module Dscf
2
+ module Marketplace
3
+ class UnitConversionSerializer < ActiveModel::Serializer
4
+ attributes :id, :from_unit_id, :to_unit_id, :conversion_factor, :notes,
5
+ :created_at, :updated_at, :reverse_conversion_factor, :description
6
+
7
+ belongs_to :from_unit
8
+ belongs_to :to_unit
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ module Dscf
2
+ module Marketplace
3
+ class UnitSerializer < ActiveModel::Serializer
4
+ attributes :id, :code, :name, :unit_type, :created_at, :updated_at, :display_name
5
+
6
+ has_many :unit_conversions
7
+ end
8
+ end
9
+ end
@@ -241,6 +241,18 @@ en:
241
241
  update: "Failed to update delivery vehicle"
242
242
  destroy: "Failed to delete delivery vehicle"
243
243
 
244
+ # Authentication
245
+ auth:
246
+ success:
247
+ otp_sent: "OTP sent successfully"
248
+ errors:
249
+ invalid_fin: "Invalid FIN number"
250
+
251
+ # Business
252
+ business:
253
+ success:
254
+ has_business_check: "Business check completed successfully"
255
+
244
256
  # Global fallback messages
245
257
  operations:
246
258
  success:
data/config/routes.rb CHANGED
@@ -16,6 +16,12 @@ Dscf::Marketplace::Engine.routes.draw do
16
16
 
17
17
  resources :unit_conversions
18
18
 
19
+ resources :businesses do
20
+ collection do
21
+ get "has_business"
22
+ end
23
+ end
24
+
19
25
  # Trading Models
20
26
  resources :supplier_products do
21
27
  resources :listings, only: [ :index ]
@@ -39,7 +45,7 @@ Dscf::Marketplace::Engine.routes.draw do
39
45
  end
40
46
  end
41
47
 
42
- resources :rfq_items, only: [ :show, :update, :destroy ]
48
+ resources :rfq_items, only: [ :index, :show, :update, :create, :destroy ]
43
49
 
44
50
  resources :quotations do
45
51
  resources :quotation_items, only: [ :index, :create ]
@@ -50,7 +56,7 @@ Dscf::Marketplace::Engine.routes.draw do
50
56
  end
51
57
  end
52
58
 
53
- resources :quotation_items, only: [ :show, :update, :destroy ]
59
+ resources :quotation_items, only: [ :index, :show, :update, :create, :destroy ]
54
60
 
55
61
  # Order Management
56
62
  resources :orders do
@@ -62,7 +68,7 @@ Dscf::Marketplace::Engine.routes.draw do
62
68
  end
63
69
  end
64
70
 
65
- resources :order_items, only: [ :show, :update ]
71
+ resources :order_items, only: [ :index, :show, :update, :create, :destroy ]
66
72
 
67
73
  # Delivery System
68
74
  resources :delivery_orders do
@@ -75,7 +81,7 @@ Dscf::Marketplace::Engine.routes.draw do
75
81
  end
76
82
  end
77
83
 
78
- resources :delivery_order_items, only: [ :show, :update ] do
84
+ resources :delivery_order_items, only: [ :index, :show, :update, :create ] do
79
85
  member do
80
86
  post "receiver_confirm"
81
87
  post "report_issue"
@@ -1,5 +1,5 @@
1
1
  module Dscf
2
2
  module Marketplace
3
- VERSION = "0.1.9".freeze
3
+ VERSION = "0.2.1".freeze
4
4
  end
5
5
  end
@@ -1,7 +1,7 @@
1
1
  FactoryBot.define do
2
2
  factory :dscf_marketplace_delivery_order_item, class: "Dscf::Marketplace::DeliveryOrderItem" do
3
3
  association :delivery_order, factory: :dscf_marketplace_delivery_order
4
- association :order_item, factory: :dscf_marketplace_order_item
4
+ association :order_item, factory: [ :dscf_marketplace_order_item, :from_listing ]
5
5
  pickup_address { create(:dscf_core_address) }
6
6
  dropoff_address { create(:dscf_core_address) }
7
7
  quantity { 10.0 }
@@ -10,8 +10,8 @@ FactoryBot.define do
10
10
 
11
11
  after(:build) do |item|
12
12
  # Only calculate subtotal if it's not explicitly set
13
- if item.subtotal.nil? && item.unit_price && item.quantity
14
- item.subtotal = item.unit_price * item.quantity
13
+ if item[:subtotal].nil? && item.unit_price && item.quantity
14
+ item.subtotal = (item.unit_price * item.quantity).round(2)
15
15
  end
16
16
  end
17
17
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dscf-marketplace
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.9
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Asrat
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-09-01 00:00:00.000000000 Z
10
+ date: 2025-09-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: rails
@@ -417,12 +417,22 @@ files:
417
417
  - MIT-LICENSE
418
418
  - Rakefile
419
419
  - app/controllers/dscf/marketplace/application_controller.rb
420
+ - app/controllers/dscf/marketplace/businesses_controller.rb
420
421
  - app/controllers/dscf/marketplace/categories_controller.rb
422
+ - app/controllers/dscf/marketplace/delivery_order_items_controller.rb
423
+ - app/controllers/dscf/marketplace/delivery_orders_controller.rb
424
+ - app/controllers/dscf/marketplace/delivery_vehicles_controller.rb
421
425
  - app/controllers/dscf/marketplace/listings_controller.rb
426
+ - app/controllers/dscf/marketplace/order_items_controller.rb
422
427
  - app/controllers/dscf/marketplace/orders_controller.rb
423
428
  - app/controllers/dscf/marketplace/products_controller.rb
429
+ - app/controllers/dscf/marketplace/quotation_items_controller.rb
424
430
  - app/controllers/dscf/marketplace/quotations_controller.rb
425
431
  - app/controllers/dscf/marketplace/request_for_quotations_controller.rb
432
+ - app/controllers/dscf/marketplace/rfq_items_controller.rb
433
+ - app/controllers/dscf/marketplace/supplier_products_controller.rb
434
+ - app/controllers/dscf/marketplace/unit_conversions_controller.rb
435
+ - app/controllers/dscf/marketplace/units_controller.rb
426
436
  - app/jobs/dscf/marketplace/application_job.rb
427
437
  - app/mailers/dscf/marketplace/application_mailer.rb
428
438
  - app/models/dscf/marketplace/application_record.rb
@@ -441,12 +451,22 @@ files:
441
451
  - app/models/dscf/marketplace/supplier_product.rb
442
452
  - app/models/dscf/marketplace/unit.rb
443
453
  - app/models/dscf/marketplace/unit_conversion.rb
454
+ - app/serializers/dscf/marketplace/business_serializer.rb
444
455
  - app/serializers/dscf/marketplace/category_serializer.rb
456
+ - app/serializers/dscf/marketplace/delivery_order_item_serializer.rb
457
+ - app/serializers/dscf/marketplace/delivery_order_serializer.rb
458
+ - app/serializers/dscf/marketplace/delivery_vehicle_serializer.rb
445
459
  - app/serializers/dscf/marketplace/listing_serializer.rb
460
+ - app/serializers/dscf/marketplace/order_item_serializer.rb
446
461
  - app/serializers/dscf/marketplace/order_serializer.rb
447
462
  - app/serializers/dscf/marketplace/product_serializer.rb
463
+ - app/serializers/dscf/marketplace/quotation_item_serializer.rb
448
464
  - app/serializers/dscf/marketplace/quotation_serializer.rb
449
465
  - app/serializers/dscf/marketplace/request_for_quotation_serializer.rb
466
+ - app/serializers/dscf/marketplace/rfq_item_serializer.rb
467
+ - app/serializers/dscf/marketplace/supplier_product_serializer.rb
468
+ - app/serializers/dscf/marketplace/unit_conversion_serializer.rb
469
+ - app/serializers/dscf/marketplace/unit_serializer.rb
450
470
  - config/locales/en.yml
451
471
  - config/routes.rb
452
472
  - db/migrate/20250827172043_create_dscf_marketplace_categories.rb