dscf-marketplace 0.1.7 → 0.1.8

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 60c2cbf7461bd253837b481338ec8105fc47e5ff3927855341efc9261bf193f5
4
- data.tar.gz: 3d10a078bab90804d176823e1cf0e44ed74f617ca3f0adeff657339438404642
3
+ metadata.gz: 9bbdcc2258fee7a63ff11ba8c87e73a47923e8dbb6d9737e55d6e3e9d7002822
4
+ data.tar.gz: 184a09306eb3c9de61c2e9edc82cdd49ed735e7bf91acae09b5ace7cd7e9f3a1
5
5
  SHA512:
6
- metadata.gz: 96051d9c835dc17d0f8c7b495c28dd48b2b45a9690711be8d9a5650f6f36643498605d4d8bfdeaf6df6a7cea2f04567b6aff8479a444c525fb68ddbc60ebf41b
7
- data.tar.gz: 6e35c21f3b43d962d838b1f5bbfb577db65e2c004c0665e340356994a93fb1e89d594d02358209af2670a6ea8638fc909347f80a8cbdd470e40d975520433af1
6
+ metadata.gz: 503e6dcdb6f209cbc278219572beb1deadbbeff8910e979914b4cd316e176528bc91130b4917bc874e3de36afb9e0f4c56978ecc3aa0dd54f4e175ee8cd2a071
7
+ data.tar.gz: e2790cb38d3a76cff511631c8b4fc7ae4b277e8faa2459241379ba3127438b242449438d363e5976dda72aa90a4d3b354e091ebf3d699bf4afb3e48a504689ef
@@ -0,0 +1,107 @@
1
+ module Dscf::Marketplace
2
+ class DeliveryOrder < ApplicationRecord
3
+ enum :status, {assigned: 0, picked_up: 1, in_transit: 2, delivered: 3, failed: 4}
4
+ enum :vehicle_type, {motorcycle: 0, car: 1, van: 2, truck: 3}
5
+
6
+ belongs_to :driver, class_name: "Dscf::Core::User"
7
+ belongs_to :pickup_address, class_name: "Dscf::Core::Address"
8
+ belongs_to :delivery_vehicle, optional: true
9
+ has_many :delivery_order_items, dependent: :destroy
10
+ has_many :marketplace_orders, class_name: "Dscf::Marketplace::Order", dependent: :nullify
11
+
12
+ validates :driver_id, presence: true
13
+ validates :pickup_address_id, presence: true
14
+ validates :status, presence: true
15
+ validates :vehicle_type, presence: true
16
+ validates :estimated_delivery_price, numericality: {greater_than_or_equal_to: 0}, allow_nil: true
17
+ validates :actual_delivery_price, numericality: {greater_than_or_equal_to: 0}, allow_nil: true
18
+
19
+ before_save :calculate_actual_delivery_price, if: :status_changed?
20
+
21
+ def pickup!
22
+ return false unless assigned?
23
+ update!(status: :picked_up, actual_delivery_time: Time.current)
24
+ true
25
+ end
26
+
27
+ def start_delivery!
28
+ return false unless picked_up?
29
+ update!(status: :in_transit)
30
+ true
31
+ end
32
+
33
+ def complete_delivery!
34
+ return false unless in_transit?
35
+ update!(status: :delivered, actual_delivery_time: Time.current)
36
+ update_associated_orders
37
+ true
38
+ end
39
+
40
+ def mark_failed!(reason = nil)
41
+ update!(status: :failed, delivery_notes: reason)
42
+ true
43
+ end
44
+
45
+ def total_items
46
+ delivery_order_items.sum(:quantity)
47
+ end
48
+
49
+ def total_orders
50
+ marketplace_orders.count
51
+ end
52
+
53
+ def delivery_duration
54
+ return nil unless actual_delivery_time && estimated_delivery_time
55
+ (actual_delivery_time - estimated_delivery_time).to_i
56
+ end
57
+
58
+ def on_time?
59
+ return nil unless actual_delivery_time && estimated_delivery_time
60
+ actual_delivery_time <= estimated_delivery_time
61
+ end
62
+
63
+ # Handoff tracking methods
64
+ def handoff_completion_status
65
+ items = delivery_order_items
66
+ {
67
+ total_items: items.count,
68
+ confirmed_items: items.count(&:receiver_confirmed?),
69
+ pending_confirmation: items.count { |item| item.delivered? && !item.receiver_confirmed? },
70
+ issues_reported: items.count(&:requires_resolution?),
71
+ completion_percentage: items.present? ? (items.count(&:receiver_confirmed?).to_f / items.count * 100).round(2) : 0
72
+ }
73
+ end
74
+
75
+ def all_handoffs_confirmed?
76
+ delivery_order_items.all?(&:receiver_confirmed?)
77
+ end
78
+
79
+ def items_requiring_attention
80
+ delivery_order_items.select(&:requires_resolution?)
81
+ end
82
+
83
+ def generate_handoff_summary_report
84
+ {
85
+ delivery_order_id: id,
86
+ driver: driver&.name,
87
+ vehicle: vehicle_type,
88
+ total_destinations: delivery_order_items.distinct.pluck(:dropoff_address_id).count,
89
+ handoff_status: handoff_completion_status,
90
+ issues: items_requiring_attention.map(&:comprehensive_damage_report),
91
+ generated_at: Time.current
92
+ }
93
+ end
94
+
95
+ private
96
+
97
+ def calculate_actual_delivery_price
98
+ self.actual_delivery_price ||= estimated_delivery_price
99
+ end
100
+
101
+ def update_associated_orders
102
+ marketplace_orders.each do |order|
103
+ order.update!(status: :completed)
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,192 @@
1
+ module Dscf::Marketplace
2
+ class DeliveryOrderItem < ApplicationRecord
3
+ enum :status, {pending: 0, picked_up: 1, delivered: 2, receiver_confirmed: 3, damaged: 4, missing: 5, disputed: 6}
4
+
5
+ belongs_to :delivery_order
6
+ belongs_to :order_item, class_name: "Dscf::Marketplace::OrderItem"
7
+ belongs_to :pickup_address, class_name: "Dscf::Core::Address"
8
+ belongs_to :dropoff_address, class_name: "Dscf::Core::Address"
9
+
10
+ validates :delivery_order_id, presence: true
11
+ validates :order_item_id, presence: true
12
+ validates :quantity, presence: true, numericality: {greater_than: 0}
13
+ validates :status, presence: true
14
+ validates :pickup_verified_quantity, numericality: {greater_than_or_equal_to: 0}, allow_nil: true
15
+ validates :dropoff_verified_quantity, numericality: {greater_than_or_equal_to: 0}, allow_nil: true
16
+ validates :damaged_quantity, numericality: {greater_than_or_equal_to: 0}, allow_nil: true
17
+ validates :missing_quantity, numericality: {greater_than_or_equal_to: 0}, allow_nil: true
18
+ validates :receiver_confirmed_by, presence: true, if: :receiver_action_taken?
19
+ validates :receiver_confirmed_at, presence: true, if: :receiver_action_taken?
20
+
21
+ before_save :calculate_verification_totals
22
+
23
+ def pending?
24
+ status == "pending"
25
+ end
26
+
27
+ def picked_up?
28
+ status == "picked_up"
29
+ end
30
+
31
+ def delivered?
32
+ status == "delivered"
33
+ end
34
+
35
+ def damaged?
36
+ status == "damaged"
37
+ end
38
+
39
+ def missing?
40
+ status == "missing"
41
+ end
42
+
43
+ def receiver_confirmed?
44
+ status == "receiver_confirmed"
45
+ end
46
+
47
+ def disputed?
48
+ status == "disputed"
49
+ end
50
+
51
+ def pickup!
52
+ return false unless pending?
53
+ update!(status: :picked_up, pickup_verified_quantity: quantity)
54
+ true
55
+ end
56
+
57
+ def deliver!
58
+ return false unless picked_up?
59
+ update!(status: :delivered, dropoff_verified_quantity: pickup_verified_quantity.to_f - (damaged_quantity || 0) - (missing_quantity || 0))
60
+ true
61
+ end
62
+
63
+ # Handoff workflow methods
64
+ def receiver_confirm!(confirmed_quantity, notes = nil, confirmed_by = nil)
65
+ return false unless delivered? || picked_up?
66
+
67
+ update!(
68
+ status: :receiver_confirmed,
69
+ dropoff_verified_quantity: confirmed_quantity,
70
+ receiver_notes: notes,
71
+ receiver_confirmed_at: Time.current,
72
+ receiver_confirmed_by: confirmed_by,
73
+ handoff_checklist_completed: true
74
+ )
75
+ notify_receiver_confirmation
76
+ true
77
+ end
78
+
79
+ def report_issue!(issue_type, quantity, description, reported_by)
80
+ return false unless delivered? || picked_up?
81
+
82
+ update!(
83
+ status: issue_type.to_sym, # :damaged or :missing
84
+ damaged_quantity: ((issue_type == "damaged") ? quantity : 0),
85
+ missing_quantity: ((issue_type == "missing") ? quantity : 0),
86
+ receiver_notes: description,
87
+ receiver_confirmed_at: Time.current,
88
+ receiver_confirmed_by: reported_by,
89
+ handoff_checklist_completed: true
90
+ )
91
+ notify_platform_of_issue
92
+ true
93
+ end
94
+
95
+ def dispute_delivery!(reason, disputed_by)
96
+ return false unless delivered? || receiver_confirmed?
97
+
98
+ update!(
99
+ status: :disputed,
100
+ receiver_notes: reason,
101
+ receiver_confirmed_at: Time.current,
102
+ receiver_confirmed_by: disputed_by
103
+ )
104
+ create_dispute_record
105
+ true
106
+ end
107
+
108
+ def mark_damaged!(quantity)
109
+ update!(status: :damaged, damaged_quantity: quantity)
110
+ true
111
+ end
112
+
113
+ def mark_missing!(quantity)
114
+ update!(status: :missing, missing_quantity: quantity)
115
+ true
116
+ end
117
+
118
+ def verification_complete?
119
+ pickup_verified_quantity.present? && dropoff_verified_quantity.present?
120
+ end
121
+
122
+ def has_discrepancy?
123
+ return false unless verification_complete?
124
+ pickup_verified_quantity != dropoff_verified_quantity
125
+ end
126
+
127
+ def discrepancy_amount
128
+ return 0 unless has_discrepancy?
129
+ (pickup_verified_quantity - dropoff_verified_quantity).abs
130
+ end
131
+
132
+ def product_name
133
+ order_item&.product_name
134
+ end
135
+
136
+ def unit_name
137
+ order_item&.unit_name
138
+ end
139
+
140
+ # Loss/Damage Reporting Methods
141
+ def comprehensive_damage_report
142
+ {
143
+ item_id: id,
144
+ product_name: order_item&.product&.name,
145
+ expected_quantity: quantity,
146
+ received_quantity: dropoff_verified_quantity,
147
+ damaged_quantity: damaged_quantity,
148
+ missing_quantity: missing_quantity,
149
+ total_discrepancy: discrepancy_amount,
150
+ issue_description: receiver_notes,
151
+ reported_at: receiver_confirmed_at,
152
+ reported_by: receiver_confirmed_by,
153
+ requires_resolution: requires_resolution?
154
+ }
155
+ end
156
+
157
+ def requires_resolution?
158
+ has_discrepancy? || damaged? || missing? || disputed?
159
+ end
160
+
161
+ private
162
+
163
+ def receiver_action_taken?
164
+ receiver_confirmed? || damaged? || missing? || disputed?
165
+ end
166
+
167
+ def notify_receiver_confirmation
168
+ # Placeholder for notification logic
169
+ # This will be implemented when we add notification system
170
+ Rails.logger.info("Receiver confirmation completed for delivery order item #{id}")
171
+ end
172
+
173
+ def notify_platform_of_issue
174
+ # Placeholder for platform notification
175
+ # This will be implemented when we add notification system
176
+ Rails.logger.info("Issue reported for delivery order item #{id}: #{status}")
177
+ end
178
+
179
+ def create_dispute_record
180
+ # Placeholder for dispute record creation
181
+ # This will be implemented when we add dispute management
182
+ Rails.logger.info("Dispute created for delivery order item #{id}")
183
+ end
184
+
185
+ def calculate_verification_totals
186
+ if pickup_verified_quantity.present? && damaged_quantity.present? && missing_quantity.present?
187
+ expected_dropoff = pickup_verified_quantity - damaged_quantity - missing_quantity
188
+ self.dropoff_verified_quantity ||= expected_dropoff
189
+ end
190
+ end
191
+ end
192
+ end
@@ -0,0 +1,61 @@
1
+ module Dscf
2
+ module Marketplace
3
+ class DeliveryVehicle < ApplicationRecord
4
+ enum :vehicle_type, {motorcycle: 0, car: 1, van: 2, truck: 3}
5
+
6
+ belongs_to :driver, class_name: "Dscf::Core::User"
7
+ has_many :delivery_orders, dependent: :nullify
8
+
9
+ validates :driver_id, presence: true
10
+ validates :plate_number, presence: true, uniqueness: true
11
+ validates :vehicle_type, presence: true
12
+ validates :year, numericality: {greater_than: 1900, less_than_or_equal_to: Time.current.year + 1}, allow_nil: true
13
+ validates :brand, length: {maximum: 50}, allow_blank: true
14
+ validates :model, length: {maximum: 50}, allow_blank: true
15
+ validates :color, length: {maximum: 30}, allow_blank: true
16
+
17
+ def motorcycle?
18
+ vehicle_type == "motorcycle"
19
+ end
20
+
21
+ def car?
22
+ vehicle_type == "car"
23
+ end
24
+
25
+ def van?
26
+ vehicle_type == "van"
27
+ end
28
+
29
+ def truck?
30
+ vehicle_type == "truck"
31
+ end
32
+
33
+ def display_name
34
+ brand_and_model = [ brand.presence, model.presence ].compact.join(" ")
35
+ brand_and_model = nil if brand_and_model.blank?
36
+ "#{brand_and_model} (#{plate_number})".strip
37
+ end
38
+
39
+ def active_deliveries
40
+ delivery_orders.where.not(status: [ :delivered, :failed ])
41
+ end
42
+
43
+ def completed_deliveries
44
+ delivery_orders.where(status: :delivered)
45
+ end
46
+
47
+ def failed_deliveries
48
+ delivery_orders.where(status: :failed)
49
+ end
50
+
51
+ def total_deliveries
52
+ delivery_orders.count
53
+ end
54
+
55
+ def success_rate
56
+ return 0 if total_deliveries.zero?
57
+ (completed_deliveries.count.to_f / total_deliveries * 100).round(2)
58
+ end
59
+ end
60
+ end
61
+ end
@@ -2,14 +2,17 @@ module Dscf::Marketplace
2
2
  class Order < ApplicationRecord
3
3
  enum :order_type, {rfq_based: 0, direct_listing: 1}
4
4
  enum :status, {pending: 0, confirmed: 1, processing: 2, completed: 3, cancelled: 4}
5
+ enum :fulfillment_type, {self_pickup: 0, delivery: 1}
5
6
 
6
7
  belongs_to :quotation, optional: true
7
8
  belongs_to :listing, optional: true
8
9
  belongs_to :user, class_name: "Dscf::Core::User"
10
+ belongs_to :delivery_order, optional: true
9
11
  has_many :order_items, dependent: :destroy
10
12
 
11
13
  validates :order_type, presence: true
12
14
  validates :status, presence: true
15
+ validates :fulfillment_type, presence: true
13
16
  validates :user, presence: true
14
17
  validate :quotation_or_listing_present
15
18
 
@@ -81,6 +84,29 @@ module Dscf::Marketplace
81
84
  end
82
85
  end
83
86
 
87
+ # Fulfillment type methods
88
+ def self_pickup?
89
+ fulfillment_type == "self_pickup"
90
+ end
91
+
92
+ def delivery?
93
+ fulfillment_type == "delivery"
94
+ end
95
+
96
+ def requires_delivery_order?
97
+ delivery? && !completed?
98
+ end
99
+
100
+ def can_be_completed?
101
+ if self_pickup?
102
+ # Self-pickup orders can be completed immediately after confirmation
103
+ confirmed? || processing?
104
+ else
105
+ # Delivery orders require delivery_order association
106
+ delivery_order.present? && delivery_order.delivered?
107
+ end
108
+ end
109
+
84
110
  def confirm!
85
111
  return false unless pending?
86
112
 
@@ -19,6 +19,14 @@ module Dscf::Marketplace
19
19
  quantity * unit_price
20
20
  end
21
21
 
22
+ def product_name
23
+ product&.name
24
+ end
25
+
26
+ def unit_name
27
+ unit&.name
28
+ end
29
+
22
30
  private
23
31
 
24
32
  def quotation_item_or_listing_present
@@ -0,0 +1,21 @@
1
+ class CreateDscfMarketplaceDeliveryOrders < ActiveRecord::Migration[8.0]
2
+ def change
3
+ create_table :dscf_marketplace_delivery_orders do |t|
4
+ t.bigint :driver_id, null: false
5
+ t.bigint :pickup_address_id, null: false
6
+ t.integer :status
7
+ t.text :delivery_notes
8
+ t.datetime :estimated_delivery_time
9
+ t.datetime :actual_delivery_time
10
+ t.decimal :estimated_delivery_price
11
+ t.decimal :actual_delivery_price
12
+ t.json :optimized_route
13
+ t.integer :vehicle_type
14
+
15
+ t.timestamps
16
+ end
17
+
18
+ add_foreign_key :dscf_marketplace_delivery_orders, :dscf_core_users, column: :driver_id
19
+ add_foreign_key :dscf_marketplace_delivery_orders, :dscf_core_addresses, column: :pickup_address_id
20
+ end
21
+ end
@@ -0,0 +1,27 @@
1
+ class CreateDscfMarketplaceDeliveryOrderItems < ActiveRecord::Migration[8.0]
2
+ def change
3
+ create_table :dscf_marketplace_delivery_order_items do |t|
4
+ t.bigint :delivery_order_id, null: false
5
+ t.bigint :order_item_id, null: false
6
+ t.bigint :pickup_address_id, null: false
7
+ t.bigint :dropoff_address_id, null: false
8
+ t.decimal :quantity
9
+ t.integer :status
10
+ t.text :notes
11
+ t.decimal :pickup_verified_quantity
12
+ t.decimal :dropoff_verified_quantity
13
+ t.decimal :damaged_quantity
14
+ t.decimal :missing_quantity
15
+ t.text :pickup_notes
16
+ t.text :dropoff_notes
17
+ t.integer :position
18
+
19
+ t.timestamps
20
+ end
21
+
22
+ add_foreign_key :dscf_marketplace_delivery_order_items, :dscf_marketplace_delivery_orders, column: :delivery_order_id
23
+ add_foreign_key :dscf_marketplace_delivery_order_items, :dscf_marketplace_order_items, column: :order_item_id
24
+ add_foreign_key :dscf_marketplace_delivery_order_items, :dscf_core_addresses, column: :pickup_address_id
25
+ add_foreign_key :dscf_marketplace_delivery_order_items, :dscf_core_addresses, column: :dropoff_address_id
26
+ end
27
+ end
@@ -0,0 +1,17 @@
1
+ class CreateDscfMarketplaceDeliveryVehicles < ActiveRecord::Migration[8.0]
2
+ def change
3
+ create_table :dscf_marketplace_delivery_vehicles do |t|
4
+ t.bigint :driver_id, null: false
5
+ t.string :plate_number
6
+ t.integer :vehicle_type
7
+ t.string :brand
8
+ t.string :model
9
+ t.integer :year
10
+ t.string :color
11
+
12
+ t.timestamps
13
+ end
14
+
15
+ add_foreign_key :dscf_marketplace_delivery_vehicles, :dscf_core_users, column: :driver_id
16
+ end
17
+ end
@@ -0,0 +1,16 @@
1
+ class AddDeliveryHandoffFieldsToDeliveryOrderItems < ActiveRecord::Migration[8.0]
2
+ def change
3
+ # Add new handoff fields
4
+ add_column :dscf_marketplace_delivery_order_items, :receiver_confirmed_at, :datetime
5
+ add_column :dscf_marketplace_delivery_order_items, :receiver_confirmed_by, :integer
6
+ add_column :dscf_marketplace_delivery_order_items, :receiver_notes, :text
7
+ add_column :dscf_marketplace_delivery_order_items, :handoff_checklist_completed, :boolean, default: false
8
+
9
+ # Add indexes for performance
10
+ add_index :dscf_marketplace_delivery_order_items, :receiver_confirmed_by
11
+ add_index :dscf_marketplace_delivery_order_items, :handoff_checklist_completed
12
+
13
+ # Note: Status enum migration handled separately to avoid data loss
14
+ # The status values will be updated in the model after this migration
15
+ end
16
+ end
@@ -0,0 +1,7 @@
1
+ class AddDeliveryOrderToOrders < ActiveRecord::Migration[8.0]
2
+ def change
3
+ add_column :dscf_marketplace_orders, :delivery_order_id, :bigint
4
+ add_foreign_key :dscf_marketplace_orders, :dscf_marketplace_delivery_orders, column: :delivery_order_id
5
+ add_index :dscf_marketplace_orders, :delivery_order_id
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ class AddDeliveryVehicleToDeliveryOrders < ActiveRecord::Migration[8.0]
2
+ def change
3
+ add_column :dscf_marketplace_delivery_orders, :delivery_vehicle_id, :bigint
4
+ add_foreign_key :dscf_marketplace_delivery_orders, :dscf_marketplace_delivery_vehicles, column: :delivery_vehicle_id
5
+ add_index :dscf_marketplace_delivery_orders, :delivery_vehicle_id
6
+ end
7
+ end
@@ -0,0 +1,6 @@
1
+ class AddFulfillmentTypeToOrders < ActiveRecord::Migration[8.0]
2
+ def change
3
+ add_column :dscf_marketplace_orders, :fulfillment_type, :integer, default: 0
4
+ add_index :dscf_marketplace_orders, :fulfillment_type
5
+ end
6
+ end
@@ -1,5 +1,5 @@
1
1
  module Dscf
2
2
  module Marketplace
3
- VERSION = "0.1.7".freeze
3
+ VERSION = "0.1.8".freeze
4
4
  end
5
5
  end
@@ -0,0 +1,15 @@
1
+ FactoryBot.define do
2
+ factory :dscf_core_address, class: "Dscf::Core::Address" do
3
+ user
4
+ address_type { 0 } # home
5
+ country { "Ethiopia" }
6
+ city { "Addis Ababa" }
7
+ sub_city { "Bole" }
8
+ woreda { "03" }
9
+ kebele { "07" }
10
+ house_numbers { "123" }
11
+ po_box { "1234" }
12
+ latitude { 9.1450 }
13
+ longitude { 38.7525 }
14
+ end
15
+ end
@@ -0,0 +1,46 @@
1
+ FactoryBot.define do
2
+ factory :dscf_marketplace_delivery_order_item, class: "Dscf::Marketplace::DeliveryOrderItem" do
3
+ association :delivery_order, factory: :dscf_marketplace_delivery_order
4
+ association :order_item, factory: :dscf_marketplace_order_item
5
+ pickup_address { create(:dscf_core_address) }
6
+ dropoff_address { create(:dscf_core_address) }
7
+ quantity { 10.0 }
8
+ status { :pending }
9
+ notes { "Test delivery item" }
10
+ pickup_verified_quantity { nil }
11
+ dropoff_verified_quantity { nil }
12
+ damaged_quantity { nil }
13
+ missing_quantity { nil }
14
+ pickup_notes { nil }
15
+ dropoff_notes { nil }
16
+ position { 1 }
17
+
18
+ trait :picked_up do
19
+ status { :picked_up }
20
+ pickup_verified_quantity { 10.0 }
21
+ end
22
+
23
+ trait :delivered do
24
+ status { :delivered }
25
+ pickup_verified_quantity { 10.0 }
26
+ dropoff_verified_quantity { 10.0 }
27
+ end
28
+
29
+ trait :receiver_confirmed do
30
+ status { :receiver_confirmed }
31
+ pickup_verified_quantity { 10.0 }
32
+ dropoff_verified_quantity { 10.0 }
33
+ receiver_confirmed_at { Time.current }
34
+ receiver_confirmed_by { create(:dscf_core_user).id }
35
+ handoff_checklist_completed { true }
36
+ end
37
+
38
+ trait :with_damage do
39
+ status { :damaged }
40
+ pickup_verified_quantity { 10.0 }
41
+ dropoff_verified_quantity { 8.0 }
42
+ damaged_quantity { 2.0 }
43
+ receiver_notes { "Package damaged during transport" }
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,14 @@
1
+ FactoryBot.define do
2
+ factory :dscf_marketplace_delivery_order, class: "Dscf::Marketplace::DeliveryOrder" do
3
+ association :driver, factory: :dscf_core_user
4
+ association :pickup_address, factory: :dscf_core_address
5
+ status { :assigned }
6
+ delivery_notes { "Test delivery order" }
7
+ estimated_delivery_time { 2.hours.from_now }
8
+ actual_delivery_time { nil }
9
+ estimated_delivery_price { 50.0 }
10
+ actual_delivery_price { nil }
11
+ optimized_route { {} }
12
+ vehicle_type { :motorcycle }
13
+ end
14
+ end
@@ -0,0 +1,37 @@
1
+ FactoryBot.define do
2
+ factory :dscf_marketplace_delivery_vehicle, class: "Dscf::Marketplace::DeliveryVehicle" do
3
+ association :driver, factory: :dscf_core_user
4
+ sequence(:plate_number) { |n| "ABC#{n.to_s.rjust(3, "0")}" }
5
+ vehicle_type { :motorcycle }
6
+ brand { "Honda" }
7
+ model { "CBR" }
8
+ year { 2020 }
9
+ color { "Red" }
10
+
11
+ trait :car do
12
+ vehicle_type { :car }
13
+ brand { "Toyota" }
14
+ model { "Corolla" }
15
+ end
16
+
17
+ trait :van do
18
+ vehicle_type { :van }
19
+ brand { "Ford" }
20
+ model { "Transit" }
21
+ end
22
+
23
+ trait :truck do
24
+ vehicle_type { :truck }
25
+ brand { "Volvo" }
26
+ model { "FH16" }
27
+ end
28
+
29
+ trait :old_vehicle do
30
+ year { 2010 }
31
+ end
32
+
33
+ trait :future_vehicle do
34
+ year { Time.current.year + 2 }
35
+ end
36
+ end
37
+ end
@@ -1,6 +1,6 @@
1
1
  FactoryBot.define do
2
2
  factory :dscf_marketplace_order_item, class: "Dscf::Marketplace::OrderItem" do
3
- # Don't create order by default, let tests specify
3
+ association :order, factory: :dscf_marketplace_order
4
4
  quantity { 5 }
5
5
  unit_price { 10.0 }
6
6
  status { :pending }
@@ -2,8 +2,9 @@ FactoryBot.define do
2
2
  factory :dscf_marketplace_order, class: "Dscf::Marketplace::Order" do
3
3
  order_type { :rfq_based }
4
4
  status { :pending }
5
+ fulfillment_type { :self_pickup }
5
6
  association :user, factory: :dscf_core_user
6
- quotation { nil }
7
+ association :quotation, factory: :dscf_marketplace_quotation
7
8
  listing { nil }
8
9
 
9
10
  trait :rfq_based do
@@ -17,6 +18,14 @@ FactoryBot.define do
17
18
  quotation { nil }
18
19
  end
19
20
 
21
+ trait :self_pickup do
22
+ fulfillment_type { :self_pickup }
23
+ end
24
+
25
+ trait :delivery do
26
+ fulfillment_type { :delivery }
27
+ end
28
+
20
29
  trait :confirmed do
21
30
  status { :confirmed }
22
31
  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.7
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Asrat
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-08-31 00:00:00.000000000 Z
10
+ date: 2025-09-01 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: rails
@@ -415,13 +415,15 @@ extensions: []
415
415
  extra_rdoc_files: []
416
416
  files:
417
417
  - MIT-LICENSE
418
- - README.md
419
418
  - Rakefile
420
419
  - app/controllers/dscf/marketplace/application_controller.rb
421
420
  - app/jobs/dscf/marketplace/application_job.rb
422
421
  - app/mailers/dscf/marketplace/application_mailer.rb
423
422
  - app/models/dscf/marketplace/application_record.rb
424
423
  - app/models/dscf/marketplace/category.rb
424
+ - app/models/dscf/marketplace/delivery_order.rb
425
+ - app/models/dscf/marketplace/delivery_order_item.rb
426
+ - app/models/dscf/marketplace/delivery_vehicle.rb
425
427
  - app/models/dscf/marketplace/listing.rb
426
428
  - app/models/dscf/marketplace/order.rb
427
429
  - app/models/dscf/marketplace/order_item.rb
@@ -449,14 +451,25 @@ files:
449
451
  - db/migrate/20250828090500_change_quotation_status_to_integer.rb
450
452
  - db/migrate/20250828115509_create_dscf_marketplace_orders.rb
451
453
  - db/migrate/20250828115525_create_dscf_marketplace_order_items.rb
454
+ - db/migrate/20250831110907_create_dscf_marketplace_delivery_orders.rb
455
+ - db/migrate/20250831110921_create_dscf_marketplace_delivery_order_items.rb
456
+ - db/migrate/20250831110933_create_dscf_marketplace_delivery_vehicles.rb
457
+ - db/migrate/20250901074509_add_delivery_handoff_fields_to_delivery_order_items.rb
458
+ - db/migrate/20250901074746_add_delivery_order_to_orders.rb
459
+ - db/migrate/20250901075511_add_delivery_vehicle_to_delivery_orders.rb
460
+ - db/migrate/20250901080134_add_fulfillment_type_to_orders.rb
452
461
  - lib/dscf/marketplace.rb
453
462
  - lib/dscf/marketplace/engine.rb
454
463
  - lib/dscf/marketplace/version.rb
455
464
  - lib/tasks/dscf/marketplace_tasks.rake
465
+ - spec/factories/dscf/core/addresses.rb
456
466
  - spec/factories/dscf/core/business_types.rb
457
467
  - spec/factories/dscf/core/businesses.rb
458
468
  - spec/factories/dscf/core/users.rb
459
469
  - spec/factories/dscf/marketplace/categories.rb
470
+ - spec/factories/dscf/marketplace/delivery_order_items.rb
471
+ - spec/factories/dscf/marketplace/delivery_orders.rb
472
+ - spec/factories/dscf/marketplace/delivery_vehicles.rb
460
473
  - spec/factories/dscf/marketplace/listings.rb
461
474
  - spec/factories/dscf/marketplace/order_items.rb
462
475
  - spec/factories/dscf/marketplace/orders.rb
data/README.md DELETED
@@ -1,28 +0,0 @@
1
- # Dscf::Marketplace
2
- Short description and motivation.
3
-
4
- ## Usage
5
- How to use my plugin.
6
-
7
- ## Installation
8
- Add this line to your application's Gemfile:
9
-
10
- ```ruby
11
- gem "dscf-marketplace"
12
- ```
13
-
14
- And then execute:
15
- ```bash
16
- $ bundle
17
- ```
18
-
19
- Or install it yourself as:
20
- ```bash
21
- $ gem install dscf-marketplace
22
- ```
23
-
24
- ## Contributing
25
- Contribution directions go here.
26
-
27
- ## License
28
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).