lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README | LICENSE

commit 329e76d4596b0333d10265e02382868667104042
parent f7a231eebdecf3632d3f6f5ef9201ac100d11b14
Author: triesap <tyson@radroots.org>
Date:   Fri, 19 Jun 2026 01:39:11 -0700

trade: expose pending order revision projection

Diffstat:
Mcrates/trade/src/order.rs | 103+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 103 insertions(+), 0 deletions(-)

diff --git a/crates/trade/src/order.rs b/crates/trade/src/order.rs @@ -702,6 +702,7 @@ pub struct RadrootsOrderProjection { pub payment: RadrootsOrderPaymentProjection, pub economics: Option<RadrootsOrderEconomics>, pub agreement_event_id: Option<RadrootsEventId>, + pub pending_revision_event_id: Option<RadrootsEventId>, pub listing_addr: Option<RadrootsListingAddress>, pub buyer_pubkey: Option<RadrootsPublicKey>, pub seller_pubkey: Option<RadrootsPublicKey>, @@ -970,6 +971,7 @@ fn reduce_grouped_order_event_records( payment: RadrootsOrderPaymentProjection::not_recorded(), economics: None, agreement_event_id: None, + pending_revision_event_id: None, listing_addr: None, buyer_pubkey: None, seller_pubkey: None, @@ -3268,6 +3270,7 @@ fn requested_projection( payment: RadrootsOrderPaymentProjection::not_recorded(), economics: Some(request.payload.economics.clone()), agreement_event_id: None, + pending_revision_event_id: None, listing_addr: Some(request.payload.listing_addr.clone()), buyer_pubkey: Some(request.payload.buyer_pubkey.clone()), seller_pubkey: Some(request.payload.seller_pubkey.clone()), @@ -3336,6 +3339,7 @@ fn decided_projection( fulfillment_status, last_event_id, agreement_event_id, + pending_revision_event_id, economics, payment, ) = match status { @@ -3519,6 +3523,7 @@ fn decided_projection( fulfillment_status, last_event_id, Some(revision_state.agreement_event_id), + revision_state.pending_revision_event_id, Some(revision_state.economics), projection_payment, ) @@ -3541,6 +3546,7 @@ fn decided_projection( Some(decision.event_id.clone()), None, None, + None, RadrootsOrderPaymentProjection::not_recorded(), ) } else { @@ -3561,6 +3567,7 @@ fn decided_projection( Some(decision.event_id.clone()), None, None, + None, RadrootsOrderPaymentProjection::not_recorded(), ), }; @@ -3580,6 +3587,7 @@ fn decided_projection( payment, economics, agreement_event_id, + pending_revision_event_id, listing_addr: Some(request.payload.listing_addr.clone()), buyer_pubkey: Some(request.payload.buyer_pubkey.clone()), seller_pubkey: Some(request.payload.seller_pubkey.clone()), @@ -3702,6 +3710,7 @@ fn cancelled_projection( payment: RadrootsOrderPaymentProjection::not_recorded(), economics: Some(economics), agreement_event_id, + pending_revision_event_id: None, listing_addr: Some(request.payload.listing_addr.clone()), buyer_pubkey: Some(request.payload.buyer_pubkey.clone()), seller_pubkey: Some(request.payload.seller_pubkey.clone()), @@ -3740,6 +3749,7 @@ fn receipt_terminal_projection( payment: RadrootsOrderPaymentProjection::not_recorded(), economics: Some(economics.clone()), agreement_event_id: Some(agreement_event_id.clone()), + pending_revision_event_id: None, listing_addr: Some(request.payload.listing_addr.clone()), buyer_pubkey: Some(request.payload.buyer_pubkey.clone()), seller_pubkey: Some(request.payload.seller_pubkey.clone()), @@ -3789,6 +3799,7 @@ fn invalid_projection_with_payment( payment, economics, agreement_event_id: None, + pending_revision_event_id: None, listing_addr: request.map(|request| request.payload.listing_addr.clone()), buyer_pubkey: request.map(|request| request.payload.buyer_pubkey.clone()), seller_pubkey: request.map(|request| request.payload.seller_pubkey.clone()), @@ -5414,6 +5425,7 @@ mod tests { projection.economics, Some(request_economics("bin-1", 2, "10")) ); + assert_eq!(projection.pending_revision_event_id, None); } #[test] @@ -5445,6 +5457,7 @@ mod tests { projection.economics, Some(request_economics("bin-1", 2, "10")) ); + assert_eq!(projection.pending_revision_event_id, None); } #[test] @@ -5614,6 +5627,43 @@ mod tests { projection.economics, Some(request_economics("bin-1", 1, "5")) ); + assert_eq!(projection.pending_revision_event_id, None); + assert!(projection.issues.is_empty()); + } + + #[test] + fn reduce_order_events_reports_pending_revision_proposal() { + let projection = reduce_order_events_with_revisions( + &order_id("order-1"), + [request_record()], + [accepted_decision_record("decision-1")], + [revision_proposal_record( + "revision-proposal-1", + "decision-1", + "revision-1", + 1, + )], + Vec::<RadrootsOrderRevisionDecisionRecord>::new(), + Vec::<RadrootsOrderFulfillmentRecord>::new(), + Vec::<RadrootsOrderCancellationRecord>::new(), + Vec::<RadrootsOrderReceiptRecord>::new(), + Vec::<RadrootsOrderPaymentEventRecord>::new(), + Vec::<RadrootsOrderSettlementRecord>::new(), + ); + + assert_eq!(projection.status, RadrootsOrderStatus::Accepted); + assert_eq!( + projection.agreement_event_id.as_ref(), + Some(&test_event_id("decision-1")) + ); + assert_eq!( + projection.last_event_id.as_ref(), + Some(&test_event_id("revision-proposal-1")) + ); + assert_eq!( + projection.pending_revision_event_id.as_ref(), + Some(&test_event_id("revision-proposal-1")) + ); assert!(projection.issues.is_empty()); } @@ -5657,6 +5707,59 @@ mod tests { projection.economics, Some(request_economics("bin-1", 2, "10")) ); + assert_eq!(projection.pending_revision_event_id, None); + assert!(projection.issues.is_empty()); + } + + #[test] + fn reduce_order_events_continues_lifecycle_after_declined_revision() { + let projection = reduce_order_events_with_revisions( + &order_id("order-1"), + [request_record()], + [accepted_decision_record("decision-1")], + [revision_proposal_record( + "revision-proposal-1", + "decision-1", + "revision-1", + 1, + )], + [revision_decision_record( + "revision-decision-1", + "revision-proposal-1", + "revision-1", + RadrootsOrderRevisionOutcome::Declined { + reason: "keep original order".to_string(), + }, + )], + [fulfillment_record( + "fulfillment-1", + "revision-decision-1", + RadrootsOrderFulfillmentState::ReadyForPickup, + )], + Vec::<RadrootsOrderCancellationRecord>::new(), + Vec::<RadrootsOrderReceiptRecord>::new(), + Vec::<RadrootsOrderPaymentEventRecord>::new(), + Vec::<RadrootsOrderSettlementRecord>::new(), + ); + + assert_eq!(projection.status, RadrootsOrderStatus::Accepted); + assert_eq!( + projection.agreement_event_id.as_ref(), + Some(&test_event_id("decision-1")) + ); + assert_eq!( + projection.fulfillment_event_id.as_ref(), + Some(&test_event_id("fulfillment-1")) + ); + assert_eq!( + projection.fulfillment_status, + Some(RadrootsOrderFulfillmentState::ReadyForPickup) + ); + assert_eq!( + projection.last_event_id.as_ref(), + Some(&test_event_id("fulfillment-1")) + ); + assert_eq!(projection.pending_revision_event_id, None); assert!(projection.issues.is_empty()); }