Class: Dscf::Marketplace::OrderSplittingService
- Inherits:
-
Object
- Object
- Dscf::Marketplace::OrderSplittingService
- Defined in:
- app/services/dscf/marketplace/order_splitting_service.rb
Class Method Summary collapse
-
.accept_item_adjustment(order, order_item) ⇒ Object
Aggregator accepts the supplier's proposal: the adjusted price/quantity become the line's actual terms, the item is confirmed, and the order total recomputes (Order#calculate_total_amount runs on save).
-
.adjust_item(order, order_item, unit_price: nil, quantity: nil, note: nil) ⇒ Object
Supplier proposes revised terms instead of confirming/rejecting outright.
-
.assign_source(order_item, source_type:, source_id:) ⇒ Object
Handles source assignment and the split operation per requirements.
-
.confirm_item(order, order_item, confirmed: true, reason: nil) ⇒ Object
Per-source confirmation (requirements doc: "Supplier and aggregator order confirmation").
- .perform_split(order) ⇒ Object
-
.reject_item_adjustment(order, order_item, reason: nil) ⇒ Object
Aggregator rejects the proposal — the line can't be fulfilled on agreeable terms, so it is cancelled (mirrors a not-confirm).
-
.reopen_item(order, order_item) ⇒ Object
Re-source loop (requirements doc: when a supplier doesn't confirm, "search for other sources" then go back to change-product-source).
- .supplier_confirm(order, confirmed: true, reason: nil) ⇒ Object
Class Method Details
.accept_item_adjustment(order, order_item) ⇒ Object
Aggregator accepts the supplier's proposal: the adjusted price/quantity become the line's actual terms, the item is confirmed, and the order total recomputes (Order#calculate_total_amount runs on save). Advances once all items responded.
89 90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'app/services/dscf/marketplace/order_splitting_service.rb', line 89 def self.accept_item_adjustment(order, order_item) order_item.unit_price = order_item.supplier_adjusted_unit_price if order_item.supplier_adjusted_unit_price.present? order_item.quantity = order_item.supplier_adjusted_quantity if order_item.supplier_adjusted_quantity.present? order_item.supplier_adjusted_unit_price = nil order_item.supplier_adjusted_quantity = nil order_item.status = :confirmed order_item.save! order.reload order.save! # recompute total_amount from the revised line order.mark_waiting_retailer_confirmation! if order.supplier_confirmation_complete? order_item end |
.adjust_item(order, order_item, unit_price: nil, quantity: nil, note: nil) ⇒ Object
Supplier proposes revised terms instead of confirming/rejecting outright. The item goes to :adjusted holding the proposal; because :adjusted is neither confirmed nor cancelled, supplier_confirmation_complete? keeps the order in waiting_supplier_confirmation until the aggregator follows up (accept/reject).
77 78 79 80 81 82 83 84 |
# File 'app/services/dscf/marketplace/order_splitting_service.rb', line 77 def self.adjust_item(order, order_item, unit_price: nil, quantity: nil, note: nil) order_item.supplier_adjusted_unit_price = unit_price if unit_price.present? order_item.supplier_adjusted_quantity = quantity if quantity.present? order_item.supplier_adjustment_note = note order_item.status = :adjusted order_item.save! order_item end |
.assign_source(order_item, source_type:, source_id:) ⇒ Object
Handles source assignment and the split operation per requirements. Sources can be:
- Aggregator self (via aggregator listing or direct)
- Sub-supplier
- Other supplier
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
# File 'app/services/dscf/marketplace/order_splitting_service.rb', line 10 def self.assign_source(order_item, source_type:, source_id:) # "self" is the frontend SourcePicker's sentinel for "the aggregator # fulfils it directly" — it is not a real polymorphic class name, so # storing it literally corrupts the source association (any later # read of order_item.source tries "self".constantize and crashes). # A self-fulfilled line has no external source at all: clear it, # matching the frontend's own isAggregatorManaged check (!source_type). if source_type.to_s == "self" order_item.source_type = nil order_item.source_id = nil else order_item.source_type = source_type order_item.source_id = source_id end order_item.save! order_item end |
.confirm_item(order, order_item, confirmed: true, reason: nil) ⇒ Object
Per-source confirmation (requirements doc: "Supplier and aggregator order confirmation"). The aggregator confirms each sub-supplier / aggregator-store allocation individually; other-supplier items are confirmed by that supplier. Once every item has responded (confirmed or cancelled), the order advances to retailer confirmation.
64 65 66 67 68 69 70 71 |
# File 'app/services/dscf/marketplace/order_splitting_service.rb', line 64 def self.confirm_item(order, order_item, confirmed: true, reason: nil) order_item.status = confirmed ? :confirmed : :cancelled order_item.save! order.reload order.mark_waiting_retailer_confirmation! if order.supplier_confirmation_complete? order_item end |
.perform_split(order) ⇒ Object
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'app/services/dscf/marketplace/order_splitting_service.rb', line 28 def self.perform_split(order) raise "Cannot split order that is not ready" unless order.all_items_validated? # Mark items ready for source assignment / supplier confirmation order.order_items.each do |item| if item.status.to_s == "pending" || item.status.to_s == "confirmed" item.status = :processing end item.save! if item.changed? end order.mark_waiting_supplier_confirmation! order end |
.reject_item_adjustment(order, order_item, reason: nil) ⇒ Object
Aggregator rejects the proposal — the line can't be fulfilled on agreeable terms, so it is cancelled (mirrors a not-confirm). Advances if all responded.
105 106 107 108 109 110 111 112 113 |
# File 'app/services/dscf/marketplace/order_splitting_service.rb', line 105 def self.reject_item_adjustment(order, order_item, reason: nil) order_item.supplier_adjustment_note = reason if reason.present? order_item.status = :cancelled order_item.save! order.reload order.mark_waiting_retailer_confirmation! if order.supplier_confirmation_complete? order_item end |
.reopen_item(order, order_item) ⇒ Object
Re-source loop (requirements doc: when a supplier doesn't confirm, "search for other sources" then go back to change-product-source). Reopens a cancelled line for a fresh source assignment: clears its source and any stale adjustment proposal, and puts it back in :processing. If the order had already advanced (because every other line had responded), pull it back to waiting_supplier_confirmation so the reassigned line gets a chance to be confirmed before the retailer sees the order.
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'app/services/dscf/marketplace/order_splitting_service.rb', line 122 def self.reopen_item(order, order_item) raise "Only a cancelled item can be reopened" unless order_item.cancelled? order_item.status = :processing order_item.source_type = nil order_item.source_id = nil order_item.supplier_adjusted_unit_price = nil order_item.supplier_adjusted_quantity = nil order_item.supplier_adjustment_note = nil order_item.save! order.reload order.mark_waiting_supplier_confirmation! unless order.waiting_supplier_confirmation? order_item end |
.supplier_confirm(order, confirmed: true, reason: nil) ⇒ Object
44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'app/services/dscf/marketplace/order_splitting_service.rb', line 44 def self.supplier_confirm(order, confirmed: true, reason: nil) if confirmed # In full impl, mark specific allocation as confirmed # For now advance whole if appropriate else order.order_items.where(status: :processing).update_all(status: OrderItem.statuses[:cancelled]) end # Check if supplier side is done if order.supplier_confirmation_complete? order.mark_waiting_retailer_confirmation! end order end |