commit 8c9c1ad86c52e90b749fd68a03493c630b7e71cf
parent 42be1a19470d6c46dec0afe51a7ba15eeffeb979
Author: triesap <tyson@radroots.org>
Date: Fri, 19 Jun 2026 20:32:35 -0700
app: prune agreement-only order state
- remove payment, settlement, receipt, and fulfillment lifecycle app surfaces
- collapse sync, SDK, store, and view projections onto request agreement flow
- update migrations and interop tests for revision and pre-agreement cancellation
- refresh UI, i18n, and source guards after deleting obsolete workflow fields
Diffstat:
28 files changed, 631 insertions(+), 6165 deletions(-)
diff --git a/crates/desktop/src/runtime.rs b/crates/desktop/src/runtime.rs
@@ -10,13 +10,11 @@ use radroots_app_core::{
AppBuildIdentity, AppDesktopRuntimePaths, AppRuntimeCapture, AppRuntimeMode,
AppRuntimePathsError, AppRuntimeSnapshot, AppSdkConfig, AppSdkDiagnostics,
AppSdkFarmPublishRequest, AppSdkLifecycleState, AppSdkListingPublishRequest,
- AppSdkOrderCancellationRequest, AppSdkOrderDecisionRequest,
- AppSdkOrderFulfillmentUpdateRequest, AppSdkOrderReceiptRecordRequest,
- AppSdkOrderRevisionDecisionRequest, AppSdkOrderRevisionProposalRequest,
- AppSdkOrderSubmitRequest, AppSdkProjectionLifecycleState, AppSdkRelayUrlPolicy, AppSdkRuntime,
- AppSdkRuntimeError, AppSdkRuntimeIssue, AppSdkRuntimeStatus, AppSdkStoragePaths,
- AppSdkWorkflowReceipt, AppSharedAccountsPaths, PackDayExportWriteError,
- prepare_pack_day_export_bundle_at_data_root,
+ AppSdkOrderCancellationRequest, AppSdkOrderDecisionRequest, AppSdkOrderRevisionDecisionRequest,
+ AppSdkOrderRevisionProposalRequest, AppSdkOrderSubmitRequest, AppSdkProjectionLifecycleState,
+ AppSdkRelayUrlPolicy, AppSdkRuntime, AppSdkRuntimeError, AppSdkRuntimeIssue,
+ AppSdkRuntimeStatus, AppSdkStoragePaths, AppSdkWorkflowReceipt, AppSharedAccountsPaths,
+ PackDayExportWriteError, prepare_pack_day_export_bundle_at_data_root,
shared_local_events_database_path_from_shared_accounts, write_prepared_pack_day_export_bundle,
};
use radroots_app_remote_signer::{
@@ -43,7 +41,6 @@ use radroots_app_state::{
use radroots_app_sync::{
AppFarmProfilePublishPayload, AppListingPublishPayload, AppOrderCancellationPublishPayload,
AppOrderDecisionInventoryCommitment, AppOrderDecisionPayload, AppOrderDecisionPublishPayload,
- AppOrderFulfillmentPublishPayload, AppOrderReceiptOutcome, AppOrderReceiptPublishPayload,
AppOrderRequestItemPayload, AppOrderRequestPublishPayload,
AppOrderRevisionDecisionPublishPayload, AppOrderRevisionProposalPublishPayload,
AppPublishContext, AppPublishPayload, AppPublishedOperationReceipt,
@@ -57,8 +54,8 @@ use radroots_app_view::{
BuyerContext, BuyerOrderDetailProjection, BuyerOrderReviewDraft, BuyerOrderStatus,
BuyerProductDetailProjection, FarmId, FarmOrderMethod, FarmProfileRecord, FarmReadiness,
FarmRulesProjection, FarmSetupDraft, FarmSetupProjection, FarmSummary, FarmerSection,
- FulfillmentWindowId, LoggedOutStartupProjection, OrderDetailProjection, OrderFulfillmentAction,
- OrderId, OrderRecoveryProjection, OrderStatus, OrdersFilter, OrdersListProjection,
+ FulfillmentWindowId, LoggedOutStartupProjection, OrderDetailProjection, OrderId,
+ OrderRecoveryProjection, OrderStatus, OrdersFilter, OrdersListProjection,
OrdersScreenQueryState, PackDayBatchPrintStatus, PackDayExportBundle, PackDayExportInstanceId,
PackDayExportStatus, PackDayHostHandoffKind, PackDayHostHandoffStatus, PackDayPrintKind,
PackDayPrintStatus, PackDayProjection, PackDayScreenQueryState, PersonalSection,
@@ -80,15 +77,11 @@ use radroots_events::{
},
kinds::{
KIND_FARM, KIND_LISTING, KIND_LISTING_DRAFT, KIND_ORDER_CANCELLATION, KIND_ORDER_DECISION,
- KIND_ORDER_FULFILLMENT_UPDATE, KIND_ORDER_PAYMENT_RECORD, KIND_ORDER_RECEIPT,
KIND_ORDER_REQUEST, KIND_ORDER_REVISION_DECISION, KIND_ORDER_REVISION_PROPOSAL,
- KIND_ORDER_SETTLEMENT_DECISION, KIND_PROFILE,
+ KIND_PROFILE,
},
};
-use radroots_events_codec::order::{
- order_event_context_from_tags, order_payment_record_from_event,
- order_settlement_decision_from_event,
-};
+use radroots_events_codec::order::order_event_context_from_tags;
use radroots_identity::{RadrootsIdentity, RadrootsIdentityId};
use radroots_local_events::{
BUYER_ORDER_REQUEST_ACTOR_SOURCE_RESOLVED_ACCOUNT,
@@ -114,25 +107,21 @@ use radroots_sdk::protocol::listing::{
};
use radroots_sdk::protocol::order::{
RadrootsOrderCancellation, RadrootsOrderDecision, RadrootsOrderDecisionOutcome,
- RadrootsOrderEconomics, RadrootsOrderFulfillmentState, RadrootsOrderFulfillmentUpdate,
- RadrootsOrderInventoryCommitment, RadrootsOrderItem, RadrootsOrderReceipt,
+ RadrootsOrderEconomics, RadrootsOrderInventoryCommitment, RadrootsOrderItem,
RadrootsOrderRequest, RadrootsOrderRevisionDecision, RadrootsOrderRevisionOutcome,
RadrootsOrderRevisionProposal,
};
use radroots_sdk::{
FARM_PUBLISH_OPERATION_KIND, LISTING_PUBLISH_OPERATION_KIND, ORDER_CANCELLATION_OPERATION_KIND,
- ORDER_DECISION_OPERATION_KIND, ORDER_FULFILLMENT_UPDATE_OPERATION_KIND,
- ORDER_RECEIPT_RECORD_OPERATION_KIND, ORDER_REVISION_DECISION_OPERATION_KIND,
+ ORDER_DECISION_OPERATION_KIND, ORDER_REVISION_DECISION_OPERATION_KIND,
ORDER_REVISION_PROPOSAL_OPERATION_KIND, ORDER_SUBMIT_OPERATION_KIND,
};
use radroots_sql_core::SqliteExecutor;
use radroots_trade::listing::parse_public_listing_address;
use radroots_trade::order::{
- RadrootsOrderCancellationRecord, RadrootsOrderDecisionRecord, RadrootsOrderFulfillmentRecord,
- RadrootsOrderPaymentEventRecord, RadrootsOrderPaymentState, RadrootsOrderReceiptRecord,
- RadrootsOrderReductionInputs, RadrootsOrderRequestRecord, RadrootsOrderRevisionDecisionRecord,
- RadrootsOrderRevisionProposalRecord, RadrootsOrderSettlementRecord, RadrootsOrderStatus,
- reduce_order_events,
+ RadrootsOrderCancellationRecord, RadrootsOrderDecisionRecord, RadrootsOrderReductionInputs,
+ RadrootsOrderRequestRecord, RadrootsOrderRevisionDecisionRecord,
+ RadrootsOrderRevisionProposalRecord, RadrootsOrderStatus, reduce_order_events,
};
use serde_json::json;
use thiserror::Error;
@@ -181,10 +170,6 @@ const APP_DIRECT_RELAY_INGEST_KINDS: &[u16] = &[
KIND_ORDER_REVISION_PROPOSAL as u16,
KIND_ORDER_REVISION_DECISION as u16,
KIND_ORDER_CANCELLATION as u16,
- KIND_ORDER_FULFILLMENT_UPDATE as u16,
- KIND_ORDER_RECEIPT as u16,
- KIND_ORDER_PAYMENT_RECORD as u16,
- KIND_ORDER_SETTLEMENT_DECISION as u16,
];
#[derive(Debug, Default)]
@@ -256,24 +241,15 @@ struct ResolvedAppOrderRevisionDecisionEvidence {
}
#[derive(Clone, Debug, Eq, PartialEq)]
-struct ResolvedAppOrderFulfillmentEvidence {
- event_id: String,
- status: RadrootsOrderFulfillmentState,
-}
-
-#[derive(Clone, Debug, Eq, PartialEq)]
struct ResolvedAppOrderLifecycleEvidence {
evidence_events: Vec<SdkRadrootsNostrEvent>,
status: RadrootsOrderStatus,
- payment_state: RadrootsOrderPaymentState,
agreement_event_id: Option<String>,
last_event_id: Option<String>,
decision: Option<ResolvedAppOrderDecisionEvidence>,
revision_proposals: Vec<ResolvedAppOrderRevisionProposalEvidence>,
revision_decisions: Vec<ResolvedAppOrderRevisionDecisionEvidence>,
- latest_fulfillment: Option<ResolvedAppOrderFulfillmentEvidence>,
cancellation_event_id: Option<String>,
- receipt_event_id: Option<String>,
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
@@ -282,11 +258,7 @@ struct AppActiveOrderEvidenceBuckets {
decisions: Vec<RadrootsOrderDecisionRecord>,
revision_proposals: Vec<RadrootsOrderRevisionProposalRecord>,
revision_decisions: Vec<RadrootsOrderRevisionDecisionRecord>,
- fulfillments: Vec<RadrootsOrderFulfillmentRecord>,
cancellations: Vec<RadrootsOrderCancellationRecord>,
- receipts: Vec<RadrootsOrderReceiptRecord>,
- payments: Vec<RadrootsOrderPaymentEventRecord>,
- settlements: Vec<RadrootsOrderSettlementRecord>,
}
#[derive(Debug, Default)]
@@ -396,8 +368,6 @@ fn publish_payload_context(publish_payload: &AppPublishPayload) -> &AppPublishCo
AppPublishPayload::OrderRevisionProposal(payload) => &payload.context,
AppPublishPayload::OrderRevisionDecision(payload) => &payload.context,
AppPublishPayload::OrderCancellation(payload) => &payload.context,
- AppPublishPayload::OrderFulfillment(payload) => &payload.context,
- AppPublishPayload::OrderReceipt(payload) => &payload.context,
}
}
@@ -866,15 +836,6 @@ impl DesktopAppRuntime {
)
}
- pub fn publish_order_fulfillment_update(
- &self,
- order_id: OrderId,
- action: OrderFulfillmentAction,
- ) -> Result<bool, AppSqliteError> {
- self.lock_state_mut()
- .publish_seller_order_fulfillment(order_id, action.fulfillment_status())
- }
-
pub fn publish_order_revision_proposal(
&self,
order_id: OrderId,
@@ -907,15 +868,6 @@ impl DesktopAppRuntime {
.publish_buyer_order_revision_decline(order_id)
}
- pub fn publish_buyer_order_receipt(
- &self,
- order_id: OrderId,
- outcome: AppOrderReceiptOutcome,
- ) -> Result<bool, AppSqliteError> {
- self.lock_state_mut()
- .publish_buyer_order_receipt(order_id, outcome)
- }
-
pub fn start_order_recovery(
&self,
order_id: OrderId,
@@ -2755,142 +2707,6 @@ impl DesktopAppRuntimeState {
Ok(true)
}
- fn prepare_seller_order_fulfillment(
- &mut self,
- order_id: OrderId,
- status: RadrootsOrderFulfillmentState,
- ) -> Result<AppOrderFulfillmentPublishPayload, AppSqliteError> {
- let _ = self.import_shared_local_events()?;
- let relay_urls = normalized_app_sync_relay_urls(&self.nostr_relay_urls).map_err(|_| {
- AppSqliteError::InvalidProjection {
- reason: "seller order fulfillment requires valid configured relays",
- }
- })?;
- if relay_urls.is_empty() {
- return Err(AppSqliteError::InvalidProjection {
- reason: "seller order fulfillment requires configured relays",
- });
- }
- self.refresh_configured_relay_state_before_order_lifecycle()?;
- let Some(sqlite_store) = self.sqlite_store.as_ref() else {
- return Err(AppSqliteError::InvalidProjection {
- reason: "seller order fulfillment requires local state",
- });
- };
- let Some(farm_id) = self.selected_farm_id() else {
- return Err(AppSqliteError::InvalidProjection {
- reason: "seller order fulfillment requires a selected farm",
- });
- };
- let Some(selected_account) = self
- .state_store
- .identity_projection()
- .selected_account
- .as_ref()
- else {
- return Err(AppSqliteError::InvalidProjection {
- reason: "seller order fulfillment requires a selected seller account",
- });
- };
- let account_id = selected_account.account.account_id.clone();
- let seller_pubkey = self.local_events_owner_pubkey(selected_account).ok_or(
- AppSqliteError::InvalidProjection {
- reason: "seller order fulfillment requires a selected seller public key",
- },
- )?;
- let request = self.resolve_seller_order_request_evidence(order_id)?;
- if request.payload.seller_pubkey.trim() != seller_pubkey.as_str() {
- return Err(AppSqliteError::InvalidProjection {
- reason: "seller order fulfillment seller account does not match order seller",
- });
- }
- let lifecycle = self.resolve_order_lifecycle_evidence(&request)?;
- let Some(decision) = lifecycle.decision.as_ref() else {
- return Err(AppSqliteError::InvalidProjection {
- reason: "seller order fulfillment requires accepted order decision evidence",
- });
- };
- if !matches!(
- decision.payload.decision,
- RadrootsOrderDecisionOutcome::Accepted { .. }
- ) {
- return Err(AppSqliteError::InvalidProjection {
- reason: "seller order fulfillment requires accepted order decision evidence",
- });
- }
- if lifecycle.cancellation_event_id.is_some() || lifecycle.receipt_event_id.is_some() {
- return Err(AppSqliteError::InvalidProjection {
- reason: "seller order fulfillment requires an active order",
- });
- }
- if lifecycle
- .latest_fulfillment
- .as_ref()
- .is_some_and(|fulfillment| {
- matches!(
- fulfillment.status,
- RadrootsOrderFulfillmentState::Delivered
- | RadrootsOrderFulfillmentState::SellerCancelled
- )
- })
- {
- return Err(AppSqliteError::InvalidProjection {
- reason: "seller order fulfillment is already terminal",
- });
- }
- if sqlite_store.load_order_detail(farm_id, order_id)?.is_none() {
- return Err(AppSqliteError::InvalidProjection {
- reason: "seller order fulfillment requires a visible seller order",
- });
- };
- if !status.is_publishable_update() {
- return Err(AppSqliteError::InvalidProjection {
- reason: "seller order fulfillment status must be publishable",
- });
- }
- let prev_event_id = match lifecycle.latest_fulfillment.as_ref() {
- Some(fulfillment) => fulfillment.event_id.clone(),
- None => active_order_current_parent_event_id(
- &lifecycle,
- "seller order fulfillment requires current lifecycle parent evidence",
- )?,
- };
- let payload = AppOrderFulfillmentPublishPayload {
- context: AppPublishContext::new(account_id, "seller_order_fulfillment"),
- app_order_id: order_id,
- farm_id,
- trade_order_id: request.payload.order_id.to_string(),
- request_event_id: request.request_event_id,
- prev_event_id,
- listing_addr: request.payload.listing_addr.to_string(),
- buyer_pubkey: request.payload.buyer_pubkey.to_string(),
- seller_pubkey: request.payload.seller_pubkey.to_string(),
- status,
- };
- AppPublishPayload::OrderFulfillment(payload.clone())
- .validate()
- .map_err(|_| AppSqliteError::InvalidProjection {
- reason: "seller order fulfillment publish payload is invalid",
- })?;
- Ok(payload)
- }
-
- fn publish_seller_order_fulfillment(
- &mut self,
- order_id: OrderId,
- status: RadrootsOrderFulfillmentState,
- ) -> Result<bool, AppSqliteError> {
- let payload = self.prepare_seller_order_fulfillment(order_id, status)?;
- let source_record_id = order_fulfillment_sdk_source_record_id(&payload);
- self.enqueue_order_fulfillment_payload_via_sdk(
- &payload,
- AppSdkMigrationReceiptSourceKind::LocalOutbox,
- source_record_id.as_str(),
- )?;
- let _ = self.refresh_selected_account_sync()?;
- Ok(true)
- }
-
fn prepare_seller_order_revision_proposal(
&mut self,
order_id: OrderId,
@@ -2965,17 +2781,9 @@ impl DesktopAppRuntimeState {
reason: "seller order revision requires accepted order decision evidence",
});
}
- if active_order_payment_blocks_lifecycle_write(&lifecycle) {
+ if lifecycle.cancellation_event_id.is_some() {
return Err(AppSqliteError::InvalidProjection {
- reason: "seller order revision requires no recorded or settled payment",
- });
- }
- if lifecycle.cancellation_event_id.is_some()
- || lifecycle.receipt_event_id.is_some()
- || lifecycle.latest_fulfillment.is_some()
- {
- return Err(AppSqliteError::InvalidProjection {
- reason: "seller order revision requires an unfulfilled active order",
+ reason: "seller order revision requires an active order",
});
}
let Some(order_detail) = sqlite_store.load_order_detail(farm_id, order_id)? else {
@@ -3112,12 +2920,9 @@ impl DesktopAppRuntimeState {
reason: "buyer order revision requires accepted order decision evidence",
});
}
- if lifecycle.cancellation_event_id.is_some()
- || lifecycle.receipt_event_id.is_some()
- || lifecycle.latest_fulfillment.is_some()
- {
+ if lifecycle.cancellation_event_id.is_some() {
return Err(AppSqliteError::InvalidProjection {
- reason: "buyer order revision requires an unfulfilled active order",
+ reason: "buyer order revision requires an active order",
});
}
let Some(proposal) = active_order_pending_revision_proposal(&lifecycle) else {
@@ -3226,12 +3031,9 @@ impl DesktopAppRuntimeState {
reason: "buyer order cancellation requires a visible buyer order",
});
};
- if !matches!(
- detail.status,
- BuyerOrderStatus::Placed | BuyerOrderStatus::Scheduled
- ) {
+ if !matches!(detail.status, BuyerOrderStatus::Placed) {
return Err(AppSqliteError::InvalidProjection {
- reason: "buyer order cancellation requires an open order",
+ reason: "buyer order cancellation requires an open pre-agreement order",
});
}
let request = self.resolve_seller_order_request_evidence(order_id)?;
@@ -3241,33 +3043,24 @@ impl DesktopAppRuntimeState {
});
}
let lifecycle = self.resolve_order_lifecycle_evidence(&request)?;
- if lifecycle.cancellation_event_id.is_some()
- || lifecycle.receipt_event_id.is_some()
- || lifecycle.latest_fulfillment.is_some()
- {
+ if lifecycle.cancellation_event_id.is_some() {
return Err(AppSqliteError::InvalidProjection {
- reason: "buyer order cancellation requires an unfulfilled order",
- });
- }
- if active_order_payment_blocks_lifecycle_write(&lifecycle) {
- return Err(AppSqliteError::InvalidProjection {
- reason: "buyer order cancellation requires no recorded or settled payment",
+ reason: "buyer order cancellation requires an open pre-agreement order",
});
}
let prev_event_id = match lifecycle.status {
RadrootsOrderStatus::Requested => request.request_event_id.clone(),
- RadrootsOrderStatus::Accepted => active_order_current_parent_event_id(
- &lifecycle,
- "buyer order cancellation requires order decision evidence",
- )?,
+ RadrootsOrderStatus::Accepted => {
+ return Err(AppSqliteError::InvalidProjection {
+ reason: "buyer order cancellation requires an open pre-agreement order",
+ });
+ }
RadrootsOrderStatus::Missing
| RadrootsOrderStatus::Declined
| RadrootsOrderStatus::Cancelled
- | RadrootsOrderStatus::Completed
- | RadrootsOrderStatus::Disputed
| RadrootsOrderStatus::Invalid => {
return Err(AppSqliteError::InvalidProjection {
- reason: "buyer order cancellation requires an open order",
+ reason: "buyer order cancellation requires an open pre-agreement order",
});
}
};
@@ -3306,124 +3099,6 @@ impl DesktopAppRuntimeState {
Ok(true)
}
- fn prepare_buyer_order_receipt(
- &mut self,
- order_id: OrderId,
- outcome: AppOrderReceiptOutcome,
- ) -> Result<AppOrderReceiptPublishPayload, AppSqliteError> {
- let _ = self.import_shared_local_events()?;
- let relay_urls = normalized_app_sync_relay_urls(&self.nostr_relay_urls).map_err(|_| {
- AppSqliteError::InvalidProjection {
- reason: "buyer order receipt requires valid configured relays",
- }
- })?;
- if relay_urls.is_empty() {
- return Err(AppSqliteError::InvalidProjection {
- reason: "buyer order receipt requires configured relays",
- });
- }
- self.refresh_configured_relay_state_before_order_lifecycle()?;
- let buyer_context = self.state_store.identity_projection().buyer_context();
- let BuyerContext::Account(account_id) = &buyer_context else {
- return Err(AppSqliteError::InvalidProjection {
- reason: "buyer order receipt requires a selected buyer account",
- });
- };
- let Some(selected_account) = self.selected_buyer_account(&buyer_context) else {
- return Err(AppSqliteError::InvalidProjection {
- reason: "buyer order receipt requires a selected buyer account",
- });
- };
- let buyer_pubkey = self.local_events_owner_pubkey(selected_account).ok_or(
- AppSqliteError::InvalidProjection {
- reason: "buyer order receipt requires a selected buyer public key",
- },
- )?;
- let Some(sqlite_store) = self.sqlite_store.as_ref() else {
- return Err(AppSqliteError::InvalidProjection {
- reason: "buyer order receipt requires local state",
- });
- };
- let buyer_order_scope = selected_buyer_order_scope(self.state_store.identity_projection());
- let Some(detail) =
- sqlite_store.load_buyer_order_detail_for_scope(&buyer_order_scope, order_id)?
- else {
- return Err(AppSqliteError::InvalidProjection {
- reason: "buyer order receipt requires a visible buyer order",
- });
- };
- let request = self.resolve_seller_order_request_evidence(order_id)?;
- if request.payload.buyer_pubkey.trim() != buyer_pubkey.as_str() {
- return Err(AppSqliteError::InvalidProjection {
- reason: "buyer order receipt buyer account does not match order buyer",
- });
- }
- let lifecycle = self.resolve_order_lifecycle_evidence(&request)?;
- if lifecycle.cancellation_event_id.is_some() || lifecycle.receipt_event_id.is_some() {
- return Err(AppSqliteError::InvalidProjection {
- reason: "buyer order receipt requires an active ready order",
- });
- }
- let fulfillment =
- lifecycle
- .latest_fulfillment
- .as_ref()
- .ok_or(AppSqliteError::InvalidProjection {
- reason: "buyer order receipt requires fulfillment evidence",
- })?;
- if !matches!(
- fulfillment.status,
- RadrootsOrderFulfillmentState::ReadyForPickup
- | RadrootsOrderFulfillmentState::Delivered
- ) {
- return Err(AppSqliteError::InvalidProjection {
- reason: "buyer order receipt requires ready fulfillment evidence",
- });
- }
- let received_at = u64::try_from(current_runtime_time_seconds()?).map_err(|_| {
- AppSqliteError::InvalidProjection {
- reason: "buyer order receipt timestamp must be non-negative",
- }
- })?;
- let received = outcome.received();
- let payload = AppOrderReceiptPublishPayload {
- context: AppPublishContext::new(account_id.clone(), "buyer_order_receipt"),
- app_order_id: order_id,
- farm_id: detail.farm_id,
- trade_order_id: request.payload.order_id.to_string(),
- request_event_id: request.request_event_id,
- prev_event_id: fulfillment.event_id.clone(),
- listing_addr: request.payload.listing_addr.to_string(),
- buyer_pubkey: request.payload.buyer_pubkey.to_string(),
- seller_pubkey: request.payload.seller_pubkey.to_string(),
- received,
- issue: outcome.issue_text(),
- received_at,
- };
- AppPublishPayload::OrderReceipt(payload.clone())
- .validate()
- .map_err(|_| AppSqliteError::InvalidProjection {
- reason: "buyer order receipt publish payload is invalid",
- })?;
- Ok(payload)
- }
-
- fn publish_buyer_order_receipt(
- &mut self,
- order_id: OrderId,
- outcome: AppOrderReceiptOutcome,
- ) -> Result<bool, AppSqliteError> {
- let payload = self.prepare_buyer_order_receipt(order_id, outcome)?;
- let source_record_id = order_receipt_sdk_source_record_id(&payload);
- self.enqueue_order_receipt_payload_via_sdk(
- &payload,
- AppSdkMigrationReceiptSourceKind::LocalOutbox,
- source_record_id.as_str(),
- )?;
- let _ = self.refresh_selected_account_sync()?;
- Ok(true)
- }
-
fn start_order_recovery(
&mut self,
order_id: OrderId,
@@ -5505,123 +5180,7 @@ impl DesktopAppRuntimeState {
}
}
- fn enqueue_order_fulfillment_payload_via_sdk(
- &self,
- payload: &AppOrderFulfillmentPublishPayload,
- source_kind: AppSdkMigrationReceiptSourceKind,
- source_record_id: &str,
- ) -> Result<(), AppSqliteError> {
- let operation_kind = ORDER_FULFILLMENT_UPDATE_OPERATION_KIND;
- let request_evidence = self.resolve_seller_order_request_evidence(payload.app_order_id)?;
- let lifecycle = self.resolve_order_lifecycle_evidence(&request_evidence)?;
- let actor_pubkey = self
- .local_signing_identity_for_publish_payload(&AppPublishPayload::OrderFulfillment(
- payload.clone(),
- ))
- .and_then(|identity| {
- let actor_pubkey = identity.public_key_hex();
- let target_relays = normalized_app_sync_relay_urls(&self.nostr_relay_urls)?;
- let request = AppSdkOrderFulfillmentUpdateRequest {
- actor_account_id: payload.context.account_id.clone(),
- actor_pubkey: actor_pubkey.clone(),
- signer_keys: identity.into_keys(),
- evidence_events: lifecycle.evidence_events,
- root_event: order_lifecycle_sdk_event_ptr(
- payload.request_event_id.as_str(),
- target_relays.as_slice(),
- "order fulfillment requires request event id",
- )?,
- previous_event: order_lifecycle_sdk_event_ptr(
- payload.prev_event_id.as_str(),
- target_relays.as_slice(),
- "order fulfillment requires previous event id",
- )?,
- fulfillment: order_fulfillment_publish_payload_to_sdk_fulfillment(payload)?,
- relay_url_policy: sdk_relay_url_policy_for_targets(target_relays.as_slice()),
- target_relays,
- idempotency_key: Some(sdk_idempotency_key(source_record_id)),
- };
- self.enqueue_app_sdk_order_fulfillment_update(request)
- .map(|receipt| (actor_pubkey, receipt))
- .map_err(sync_transport_error_from_sdk_runtime_error)
- });
- match actor_pubkey {
- Ok((actor_pubkey, receipt)) => self.record_app_sdk_migration_success(
- source_kind,
- source_record_id,
- operation_kind,
- actor_pubkey.as_str(),
- &receipt,
- ),
- Err(error) => self.record_app_sdk_migration_failure(
- source_kind,
- source_record_id,
- operation_kind,
- None,
- sync_transport_error_detail_json(&error),
- ),
- }
- }
-
- fn enqueue_order_receipt_payload_via_sdk(
- &self,
- payload: &AppOrderReceiptPublishPayload,
- source_kind: AppSdkMigrationReceiptSourceKind,
- source_record_id: &str,
- ) -> Result<(), AppSqliteError> {
- let operation_kind = ORDER_RECEIPT_RECORD_OPERATION_KIND;
- let request_evidence = self.resolve_seller_order_request_evidence(payload.app_order_id)?;
- let lifecycle = self.resolve_order_lifecycle_evidence(&request_evidence)?;
- let actor_pubkey = self
- .local_signing_identity_for_publish_payload(&AppPublishPayload::OrderReceipt(
- payload.clone(),
- ))
- .and_then(|identity| {
- let actor_pubkey = identity.public_key_hex();
- let target_relays = normalized_app_sync_relay_urls(&self.nostr_relay_urls)?;
- let request = AppSdkOrderReceiptRecordRequest {
- actor_account_id: payload.context.account_id.clone(),
- actor_pubkey: actor_pubkey.clone(),
- signer_keys: identity.into_keys(),
- evidence_events: lifecycle.evidence_events,
- root_event: order_lifecycle_sdk_event_ptr(
- payload.request_event_id.as_str(),
- target_relays.as_slice(),
- "order receipt requires request event id",
- )?,
- previous_event: order_lifecycle_sdk_event_ptr(
- payload.prev_event_id.as_str(),
- target_relays.as_slice(),
- "order receipt requires previous event id",
- )?,
- receipt: order_receipt_publish_payload_to_sdk_receipt(payload)?,
- relay_url_policy: sdk_relay_url_policy_for_targets(target_relays.as_slice()),
- target_relays,
- idempotency_key: Some(sdk_idempotency_key(source_record_id)),
- };
- self.enqueue_app_sdk_order_receipt_record(request)
- .map(|receipt| (actor_pubkey, receipt))
- .map_err(sync_transport_error_from_sdk_runtime_error)
- });
- match actor_pubkey {
- Ok((actor_pubkey, receipt)) => self.record_app_sdk_migration_success(
- source_kind,
- source_record_id,
- operation_kind,
- actor_pubkey.as_str(),
- &receipt,
- ),
- Err(error) => self.record_app_sdk_migration_failure(
- source_kind,
- source_record_id,
- operation_kind,
- None,
- sync_transport_error_detail_json(&error),
- ),
- }
- }
-
- fn local_signing_identity_for_publish_payload(
+ fn local_signing_identity_for_publish_payload(
&self,
payload: &AppPublishPayload,
) -> Result<RadrootsIdentity, AppSyncTransportError> {
@@ -5680,20 +5239,6 @@ impl DesktopAppRuntimeState {
self.with_app_sdk_runtime(|runtime| runtime.enqueue_order_cancellation(request))
}
- fn enqueue_app_sdk_order_fulfillment_update(
- &self,
- request: AppSdkOrderFulfillmentUpdateRequest,
- ) -> Result<AppSdkWorkflowReceipt, AppSdkRuntimeError> {
- self.with_app_sdk_runtime(|runtime| runtime.enqueue_order_fulfillment_update(request))
- }
-
- fn enqueue_app_sdk_order_receipt_record(
- &self,
- request: AppSdkOrderReceiptRecordRequest,
- ) -> Result<AppSdkWorkflowReceipt, AppSdkRuntimeError> {
- self.with_app_sdk_runtime(|runtime| runtime.enqueue_order_receipt_record(request))
- }
-
fn with_app_sdk_runtime<T>(
&self,
command: impl FnOnce(&AppSdkRuntime) -> Result<T, AppSdkRuntimeError>,
@@ -6290,73 +5835,6 @@ impl DesktopAppRuntimeState {
payload: envelope.payload,
});
}
- KIND_ORDER_FULFILLMENT_UPDATE => {
- let Ok(envelope) =
- radroots_sdk::protocol::order::parse_fulfillment_update(&event)
- else {
- return Err(AppSqliteError::InvalidProjection {
- reason: "order lifecycle evidence is invalid",
- });
- };
- let context = active_order_event_record_context(&event, envelope.message_type)?;
- buckets.fulfillments.push(RadrootsOrderFulfillmentRecord {
- event_id,
- author_pubkey,
- counterparty_pubkey: context.0,
- root_event_id: context.1,
- prev_event_id: context.2,
- payload: envelope.payload,
- });
- }
- KIND_ORDER_RECEIPT => {
- let Ok(envelope) = radroots_sdk::protocol::order::parse_buyer_receipt(&event)
- else {
- return Err(AppSqliteError::InvalidProjection {
- reason: "order lifecycle evidence is invalid",
- });
- };
- let context = active_order_event_record_context(&event, envelope.message_type)?;
- buckets.receipts.push(RadrootsOrderReceiptRecord {
- event_id,
- author_pubkey,
- counterparty_pubkey: context.0,
- root_event_id: context.1,
- prev_event_id: context.2,
- payload: envelope.payload,
- });
- }
- KIND_ORDER_PAYMENT_RECORD => {
- let envelope = order_payment_record_from_event(&event).map_err(|_| {
- AppSqliteError::InvalidProjection {
- reason: "order lifecycle evidence is invalid",
- }
- })?;
- let context = active_order_event_record_context(&event, envelope.message_type)?;
- buckets.payments.push(RadrootsOrderPaymentEventRecord {
- event_id,
- author_pubkey,
- counterparty_pubkey: context.0,
- root_event_id: context.1,
- prev_event_id: context.2,
- payload: envelope.payload,
- });
- }
- KIND_ORDER_SETTLEMENT_DECISION => {
- let envelope = order_settlement_decision_from_event(&event).map_err(|_| {
- AppSqliteError::InvalidProjection {
- reason: "order lifecycle evidence is invalid",
- }
- })?;
- let context = active_order_event_record_context(&event, envelope.message_type)?;
- buckets.settlements.push(RadrootsOrderSettlementRecord {
- event_id,
- author_pubkey,
- counterparty_pubkey: context.0,
- root_event_id: context.1,
- prev_event_id: context.2,
- payload: envelope.payload,
- });
- }
_ => {}
}
}
@@ -6368,11 +5846,7 @@ impl DesktopAppRuntimeState {
decisions: buckets.decisions.clone(),
revision_proposals: buckets.revision_proposals.clone(),
revision_decisions: buckets.revision_decisions.clone(),
- fulfillments: buckets.fulfillments.clone(),
cancellations: buckets.cancellations.clone(),
- receipts: buckets.receipts.clone(),
- payments: buckets.payments.clone(),
- settlements: buckets.settlements.clone(),
},
);
if !projection.issues.is_empty() || projection.status == RadrootsOrderStatus::Invalid {
@@ -6403,28 +5877,9 @@ impl DesktopAppRuntimeState {
})
})
.transpose()?;
- let latest_fulfillment = projection
- .fulfillment_event_id
- .as_ref()
- .map(|event_id| {
- buckets
- .fulfillments
- .iter()
- .find(|fulfillment| fulfillment.event_id == *event_id)
- .map(|fulfillment| ResolvedAppOrderFulfillmentEvidence {
- event_id: fulfillment.event_id.to_string(),
- status: fulfillment.payload.status,
- })
- .ok_or(AppSqliteError::InvalidProjection {
- reason: "order lifecycle evidence is invalid",
- })
- })
- .transpose()?;
-
Ok(ResolvedAppOrderLifecycleEvidence {
evidence_events,
status: projection.status,
- payment_state: projection.payment.state,
agreement_event_id: projection
.agreement_event_id
.map(|event_id| event_id.to_string()),
@@ -6448,13 +5903,9 @@ impl DesktopAppRuntimeState {
payload: decision.payload,
})
.collect(),
- latest_fulfillment,
cancellation_event_id: projection
.cancellation_event_id
.map(|event_id| event_id.to_string()),
- receipt_event_id: projection
- .receipt_event_id
- .map(|event_id| event_id.to_string()),
})
}
@@ -6468,10 +5919,6 @@ impl DesktopAppRuntimeState {
KIND_ORDER_REVISION_PROPOSAL,
KIND_ORDER_REVISION_DECISION,
KIND_ORDER_CANCELLATION,
- KIND_ORDER_FULFILLMENT_UPDATE,
- KIND_ORDER_RECEIPT,
- KIND_ORDER_PAYMENT_RECORD,
- KIND_ORDER_SETTLEMENT_DECISION,
];
if let Some(sqlite_store) = self.sqlite_store.as_ref() {
@@ -8083,18 +7530,6 @@ fn order_cancellation_sdk_source_record_id(payload: &AppOrderCancellationPublish
format!("app:order_cancellation:{}", payload.app_order_id)
}
-fn order_fulfillment_sdk_source_record_id(payload: &AppOrderFulfillmentPublishPayload) -> String {
- format!(
- "app:order_fulfillment:{}:{}",
- payload.app_order_id,
- order_fulfillment_status_storage_key(payload.status)
- )
-}
-
-fn order_receipt_sdk_source_record_id(payload: &AppOrderReceiptPublishPayload) -> String {
- format!("app:order_receipt:{}", payload.app_order_id)
-}
-
fn sdk_relay_url_policy_for_targets(target_relays: &[String]) -> AppSdkRelayUrlPolicy {
if target_relays
.iter()
@@ -8471,17 +7906,6 @@ fn order_lifecycle_sdk_event_ptr(
})
}
-fn order_fulfillment_status_storage_key(status: RadrootsOrderFulfillmentState) -> &'static str {
- match status {
- RadrootsOrderFulfillmentState::AcceptedNotFulfilled => "accepted_not_fulfilled",
- RadrootsOrderFulfillmentState::Preparing => "preparing",
- RadrootsOrderFulfillmentState::ReadyForPickup => "ready_for_pickup",
- RadrootsOrderFulfillmentState::OutForDelivery => "out_for_delivery",
- RadrootsOrderFulfillmentState::Delivered => "delivered",
- RadrootsOrderFulfillmentState::SellerCancelled => "seller_cancelled",
- }
-}
-
#[cfg(test)]
fn selected_listing_relay(
listing_relays: &[String],
@@ -8791,10 +8215,6 @@ fn buyer_order_request_local_work_payload(
"order_updated_at": order.updated_at,
"created_at_ms": timestamp,
},
- "payment_display": {
- "state": "not_recorded",
- "allows_payment_action": false,
- },
"document": {
"version": 1,
"kind": BUYER_ORDER_REQUEST_DOCUMENT_KIND,
@@ -9376,13 +8796,11 @@ fn load_selected_account_reminder_context_with_options(
.items
.iter()
.filter(|item| {
- !matches!(
- item.kind,
- ReminderKind::MissedPickupRecovery | ReminderKind::RefundRecovery
- ) && matches!(
- item.urgency,
- ReminderUrgency::DueSoon | ReminderUrgency::Overdue | ReminderUrgency::Blocking
- )
+ !matches!(item.kind, ReminderKind::MissedPickupRecovery)
+ && matches!(
+ item.urgency,
+ ReminderUrgency::DueSoon | ReminderUrgency::Overdue | ReminderUrgency::Blocking
+ )
})
.count() as u32;
let recovery_actions_open = recovery_queue
@@ -9538,7 +8956,6 @@ fn derive_selected_account_reminder_schedule(
{
let kind = match record.kind {
RecoveryKind::MissedPickup => ReminderKind::MissedPickupRecovery,
- RecoveryKind::RefundFollowUp => ReminderKind::RefundRecovery,
};
items.push(build_reminder_projection(
farm_id,
@@ -9852,7 +9269,6 @@ fn ordered_order_recoveries_for_detail(
fn order_recovery_kind_rank(kind: RecoveryKind) -> u8 {
match kind {
RecoveryKind::MissedPickup => 0,
- RecoveryKind::RefundFollowUp => 1,
}
}
@@ -9865,13 +9281,6 @@ fn order_recovery_summary(kind: RecoveryKind, state: RecoveryState) -> &'static
(RecoveryKind::MissedPickup, RecoveryState::Resolved) => {
"Missed pickup follow-up is resolved"
}
- (RecoveryKind::RefundFollowUp, RecoveryState::Open) => "Payment status follow-up is open",
- (RecoveryKind::RefundFollowUp, RecoveryState::InReview) => {
- "Payment status follow-up is in review"
- }
- (RecoveryKind::RefundFollowUp, RecoveryState::Resolved) => {
- "Payment status follow-up is resolved"
- }
}
}
@@ -9886,15 +9295,6 @@ fn order_recovery_note(kind: RecoveryKind, state: RecoveryState) -> &'static str
(RecoveryKind::MissedPickup, RecoveryState::Resolved) => {
"The seller and buyer have agreed on the next step."
}
- (RecoveryKind::RefundFollowUp, RecoveryState::Open) => {
- "Review the order record and agree on the next step."
- }
- (RecoveryKind::RefundFollowUp, RecoveryState::InReview) => {
- "Confirm the outcome with the order parties."
- }
- (RecoveryKind::RefundFollowUp, RecoveryState::Resolved) => {
- "The payment status follow-up is resolved."
- }
}
}
@@ -10352,25 +9752,6 @@ fn active_order_event_record_context(
Ok((context.counterparty_pubkey, root_event_id, prev_event_id))
}
-fn active_order_current_parent_event_id(
- lifecycle: &ResolvedAppOrderLifecycleEvidence,
- reason: &'static str,
-) -> Result<String, AppSqliteError> {
- lifecycle
- .last_event_id
- .clone()
- .ok_or(AppSqliteError::InvalidProjection { reason })
-}
-
-fn active_order_payment_blocks_lifecycle_write(
- lifecycle: &ResolvedAppOrderLifecycleEvidence,
-) -> bool {
- !matches!(
- lifecycle.payment_state,
- RadrootsOrderPaymentState::NotRecorded
- )
-}
-
fn active_order_revision_parent_event_id(
lifecycle: &ResolvedAppOrderLifecycleEvidence,
) -> Option<String> {
@@ -10584,18 +9965,6 @@ fn order_revision_decision_publish_payload_to_sdk_revision_decision(
})
}
-fn order_fulfillment_publish_payload_to_sdk_fulfillment(
- payload: &AppOrderFulfillmentPublishPayload,
-) -> Result<RadrootsOrderFulfillmentUpdate, AppSyncTransportError> {
- Ok(RadrootsOrderFulfillmentUpdate {
- order_id: publish_order_id(payload.trade_order_id.as_str())?,
- listing_addr: publish_listing_addr(payload.listing_addr.as_str())?,
- buyer_pubkey: publish_pubkey(payload.buyer_pubkey.as_str())?,
- seller_pubkey: publish_pubkey(payload.seller_pubkey.as_str())?,
- status: payload.status,
- })
-}
-
fn order_cancellation_publish_payload_to_sdk_cancellation(
payload: &AppOrderCancellationPublishPayload,
) -> Result<RadrootsOrderCancellation, AppSyncTransportError> {
@@ -10608,20 +9977,6 @@ fn order_cancellation_publish_payload_to_sdk_cancellation(
})
}
-fn order_receipt_publish_payload_to_sdk_receipt(
- payload: &AppOrderReceiptPublishPayload,
-) -> Result<RadrootsOrderReceipt, AppSyncTransportError> {
- Ok(RadrootsOrderReceipt {
- order_id: publish_order_id(payload.trade_order_id.as_str())?,
- listing_addr: publish_listing_addr(payload.listing_addr.as_str())?,
- buyer_pubkey: publish_pubkey(payload.buyer_pubkey.as_str())?,
- seller_pubkey: publish_pubkey(payload.seller_pubkey.as_str())?,
- received: payload.received,
- issue: payload.issue.clone(),
- received_at: payload.received_at,
- })
-}
-
fn pending_sync_upsert(aggregate: SyncAggregateRef, payload_json: String) -> PendingSyncOperation {
let created_at = current_utc_timestamp();
@@ -10706,8 +10061,7 @@ mod tests {
use radroots_app_sync::{
AppFarmProfilePublishPayload, AppListingPublishPayload, AppOrderCancellationPublishPayload,
AppOrderDecisionInventoryCommitment, AppOrderDecisionPayload,
- AppOrderDecisionPublishPayload, AppOrderFulfillmentPublishPayload, AppOrderReceiptOutcome,
- AppOrderReceiptPublishPayload, AppOrderRequestItemPayload, AppOrderRequestPublishPayload,
+ AppOrderDecisionPublishPayload, AppOrderRequestItemPayload, AppOrderRequestPublishPayload,
AppOrderRevisionDecisionPublishPayload, AppOrderRevisionProposalPublishPayload,
AppPublishContext, AppPublishPayload, AppPublishedOperationReceipt,
AppRelayIngestScopeFreshness, AppRelayIngestScopeStatus, AppSyncRequest, AppSyncResult,
@@ -10723,10 +10077,10 @@ mod tests {
BuyerOrderStatus, FarmId, FarmOperatingRulesRecord, FarmOrderMethod, FarmProfileRecord,
FarmReadiness, FarmReadinessBlocker, FarmRulesProjection, FarmSetupDraft,
FarmSetupProjection, FarmSummary, FarmerActivationProjection, FarmerSection,
- FulfillmentWindowId, FulfillmentWindowRecord, LoggedOutStartupProjection,
- OrderFulfillmentAction, OrderId, OrderStatus, OrdersFilter, PackDayBatchPrintArtifact,
- PackDayBatchPrintFailureKind, PackDayBatchPrintStatus, PackDayExportInstanceId,
- PackDayExportStatus, PackDayHostHandoffKind, PackDayHostHandoffStatus, PackDayPackListRow,
+ FulfillmentWindowId, FulfillmentWindowRecord, LoggedOutStartupProjection, OrderId,
+ OrderStatus, OrdersFilter, PackDayBatchPrintArtifact, PackDayBatchPrintFailureKind,
+ PackDayBatchPrintStatus, PackDayExportInstanceId, PackDayExportStatus,
+ PackDayHostHandoffKind, PackDayHostHandoffStatus, PackDayPackListRow,
PackDayPrintFailureKind, PackDayPrintKind, PackDayPrintStatus, PackDayProductTotalRow,
PackDayProjection, PackDayRosterRow, PersonalSection, PickupLocationId,
PickupLocationRecord, ProductEditorDraft, ProductId, ProductPublishBlocker, ProductStatus,
@@ -10739,11 +10093,8 @@ mod tests {
RadrootsCoreCurrency, RadrootsCoreDecimal, RadrootsCoreMoney, RadrootsCoreUnit,
};
use radroots_events::ids::{
- RadrootsEconomicsDigest, RadrootsEventId, RadrootsInventoryBinId, RadrootsListingAddress,
- RadrootsOrderId, RadrootsOrderQuoteId, RadrootsOrderRevisionId, RadrootsPublicKey,
- };
- use radroots_events_codec::order::{
- order_payment_record_event_build, order_settlement_decision_event_build,
+ RadrootsEventId, RadrootsInventoryBinId, RadrootsListingAddress, RadrootsOrderId,
+ RadrootsOrderQuoteId, RadrootsOrderRevisionId, RadrootsPublicKey,
};
use radroots_events_codec::wire::WireEventParts;
use radroots_identity::{RadrootsIdentity, RadrootsIdentityId};
@@ -10766,21 +10117,16 @@ mod tests {
};
use radroots_sdk::protocol::order::{
RadrootsOrderCancellation, RadrootsOrderDecision, RadrootsOrderDecisionOutcome,
- RadrootsOrderEconomicItem, RadrootsOrderEconomics, RadrootsOrderFulfillmentState,
- RadrootsOrderFulfillmentUpdate, RadrootsOrderInventoryCommitment, RadrootsOrderItem,
- RadrootsOrderPaymentMethod, RadrootsOrderPaymentRecord, RadrootsOrderPricingBasis,
- RadrootsOrderReceipt, RadrootsOrderRequest, RadrootsOrderRevisionDecision,
- RadrootsOrderRevisionOutcome, RadrootsOrderRevisionProposal,
- RadrootsOrderSettlementDecision, RadrootsOrderSettlementOutcome,
+ RadrootsOrderEconomicItem, RadrootsOrderEconomics, RadrootsOrderInventoryCommitment,
+ RadrootsOrderItem, RadrootsOrderPricingBasis, RadrootsOrderRequest,
+ RadrootsOrderRevisionDecision, RadrootsOrderRevisionOutcome, RadrootsOrderRevisionProposal,
};
use radroots_sdk::{
LISTING_PUBLISH_OPERATION_KIND, ORDER_CANCELLATION_OPERATION_KIND,
- ORDER_DECISION_OPERATION_KIND, ORDER_FULFILLMENT_UPDATE_OPERATION_KIND,
- ORDER_RECEIPT_RECORD_OPERATION_KIND, ORDER_REVISION_DECISION_OPERATION_KIND,
+ ORDER_DECISION_OPERATION_KIND, ORDER_REVISION_DECISION_OPERATION_KIND,
ORDER_SUBMIT_OPERATION_KIND,
};
use radroots_sql_core::{SqlExecutor, SqliteExecutor};
- use radroots_trade::order::radroots_order_economics_digest;
use serde_json::json;
use tokio::net::TcpListener;
use tokio::sync::oneshot;
@@ -10805,8 +10151,8 @@ mod tests {
DesktopAppSdkDiagnosticsState, DesktopAppSyncStatusSummary, DesktopRemoteSignerPaths,
SYNC_TRANSPORT_UNAVAILABLE_MESSAGE, TokioRuntimeBuilder, default_sync_transport,
direct_relay_event_source_runtime, farm_sync_payload, is_hex_64,
- order_decision_publish_payload_to_sdk_decision, order_fulfillment_status_storage_key,
- pending_sync_upsert, signed_event_from_local_record,
+ order_decision_publish_payload_to_sdk_decision, pending_sync_upsert,
+ signed_event_from_local_record,
};
use crate::pack_day_host_handoff::PackDayHostHandoffError;
use crate::pack_day_print::{
@@ -10956,13 +10302,6 @@ mod tests {
fn event_count(&self) -> usize {
self.events.lock().expect("relay events lock").len()
}
-
- fn push_event(&self, event: &radroots_nostr::prelude::RadrootsNostrEvent) {
- self.events
- .lock()
- .expect("relay events lock")
- .push(serde_json::to_value(event).expect("relay event json"));
- }
}
fn relay_event_matches_filters(
@@ -11209,10 +10548,6 @@ mod tests {
RadrootsListingAddress::parse(value).expect("listing address")
}
- fn test_economics_digest(value: impl AsRef<str>) -> RadrootsEconomicsDigest {
- RadrootsEconomicsDigest::parse(value).expect("economics digest")
- }
-
fn install_recorded_sync_transport(
runtime: &DesktopAppRuntime,
transport: RecordedAppSyncTransport,
@@ -11564,48 +10899,13 @@ mod tests {
seller_pubkey: common.6.clone(),
reason: "buyer cancelled order".to_owned(),
});
- let fulfillment = AppPublishPayload::OrderFulfillment(AppOrderFulfillmentPublishPayload {
- context: AppPublishContext::new(
- seller_account_id.to_string(),
- "seller_order_fulfillment",
- ),
- app_order_id: common.0,
- farm_id: common.1,
- trade_order_id: common.2.clone(),
- request_event_id: common.3.clone(),
- prev_event_id: test_event_id_seed("order-decision-event-1"),
- listing_addr: common.4.clone(),
- buyer_pubkey: common.5.clone(),
- seller_pubkey: common.6.clone(),
- status: RadrootsOrderFulfillmentState::ReadyForPickup,
- });
- let receipt = AppPublishPayload::OrderReceipt(AppOrderReceiptPublishPayload {
- context: AppPublishContext::new(buyer_account_id.to_string(), "buyer_order_receipt"),
- app_order_id: common.0,
- farm_id: common.1,
- trade_order_id: common.2.clone(),
- request_event_id: common.3.clone(),
- prev_event_id: test_event_id_seed("fulfillment-event-1"),
- listing_addr: common.4.clone(),
- buyer_pubkey: common.5.clone(),
- seller_pubkey: common.6.clone(),
- received: true,
- issue: None,
- received_at: 1_785_000_000,
- });
- let operations = [
- revision_proposal,
- revision_decision,
- cancellation,
- fulfillment,
- receipt,
- ]
- .into_iter()
- .map(|payload| {
- PendingSyncOperation::from_publish_payload(payload, "2026-05-24T12:00:00Z")
- .expect("typed lifecycle publish work should serialize")
- })
- .collect::<Vec<_>>();
+ let operations = [revision_proposal, revision_decision, cancellation]
+ .into_iter()
+ .map(|payload| {
+ PendingSyncOperation::from_publish_payload(payload, "2026-05-24T12:00:00Z")
+ .expect("typed lifecycle publish work should serialize")
+ })
+ .collect::<Vec<_>>();
let mut transport =
ConfiguredRelayAppSyncTransport::with_relay_urls(manager, vec![relay.url().to_owned()]);
@@ -16507,164 +15807,16 @@ mod tests {
}
#[test]
- fn runtime_publishes_all_seller_fulfillment_states_and_projects_signed_evidence() {
- for (label, action, expected_status) in [
- (
- "preparing",
- OrderFulfillmentAction::Preparing,
- RadrootsOrderFulfillmentState::Preparing,
- ),
- (
- "ready_for_pickup",
- OrderFulfillmentAction::ReadyForPickup,
- RadrootsOrderFulfillmentState::ReadyForPickup,
- ),
- (
- "out_for_delivery",
- OrderFulfillmentAction::OutForDelivery,
- RadrootsOrderFulfillmentState::OutForDelivery,
- ),
- (
- "delivered",
- OrderFulfillmentAction::Delivered,
- RadrootsOrderFulfillmentState::Delivered,
- ),
- (
- "seller_cancelled",
- OrderFulfillmentAction::SellerCancelled,
- RadrootsOrderFulfillmentState::SellerCancelled,
- ),
- ] {
- let relay = ThreadedAckRelay::spawn();
- let runtime_label = format!("seller_order_fulfillment_publish_{label}");
- let (runtime, paths, order_id, product_id, seller_pubkey, buyer_pubkey) =
- seller_order_decision_runtime(runtime_label.as_str(), 6, 2);
- install_direct_relay_sync_transport(&runtime, &relay);
- publish_prior_relay_seller_order_accept(
- &runtime,
- &relay,
- order_id,
- product_id,
- seller_pubkey.as_str(),
- buyer_pubkey.as_str(),
- );
-
- assert!(
- runtime
- .publish_order_fulfillment_update(order_id, action)
- .expect("seller fulfillment update should publish")
- );
-
- assert_eq!(persisted_order_status(&runtime, order_id), "scheduled");
- assert_eq!(relay.event_count(), 1);
- let fulfillment_events =
- shared_order_events_by_kind(&paths, 3433, seller_pubkey.as_str());
- assert!(fulfillment_events.is_empty());
- assert_order_fulfillment_sdk_migration_receipt(
- &runtime,
- order_id,
- expected_status,
- AppSdkMigrationState::Enqueued,
- );
-
- cleanup_bootstrapped_runtime_paths(&paths);
- }
- }
-
- #[test]
- fn runtime_publishes_seller_order_fulfillment_ready_from_revision_parent() {
- for (label, revision_decision) in [
- ("accepted", RadrootsOrderRevisionOutcome::Accepted),
- (
- "declined",
- RadrootsOrderRevisionOutcome::Declined {
- reason: "keep original order".to_owned(),
- },
- ),
- ] {
- let relay = ThreadedAckRelay::spawn();
- let runtime_label = format!("seller_order_fulfillment_revision_parent_{label}");
- let (runtime, paths, order_id, product_id, seller_pubkey, buyer_pubkey) =
- seller_order_decision_runtime(runtime_label.as_str(), 6, 2);
- install_direct_relay_sync_transport(&runtime, &relay);
- let listing_key = super::d_tag_from_uuid(product_id.as_uuid());
- let listing_addr = format!("30402:{seller_pubkey}:{listing_key}");
- let request_event_id = shared_order_request_event_id(&paths, "seller-order-decision-1");
- let request_event_id = request_event_id.as_str();
- let decision_event_id = append_signed_order_decision_record(
- &paths,
- "seller-order-decision-1",
- request_event_id,
- listing_addr.as_str(),
- buyer_pubkey.as_str(),
- seller_pubkey.as_str(),
- 2,
- );
- let proposal_key = format!("seller-order-ready-revision-{label}-proposal");
- let proposal_event_id = append_signed_order_revision_proposal_record_with_prev(
- &paths,
- "seller-order-decision-1",
- proposal_key.as_str(),
- request_event_id,
- decision_event_id.as_str(),
- listing_addr.as_str(),
- buyer_pubkey.as_str(),
- seller_pubkey.as_str(),
- );
- let revision_id = format!("revision-{proposal_key}");
- let _revision_decision_event_id =
- append_signed_order_revision_decision_record_with_prev(
- &paths,
- "seller-order-decision-1",
- format!("seller-order-ready-revision-{label}-decision").as_str(),
- request_event_id,
- proposal_event_id.as_str(),
- revision_id.as_str(),
- listing_addr.as_str(),
- buyer_pubkey.as_str(),
- seller_pubkey.as_str(),
- revision_decision,
- );
- runtime
- .refresh_shared_local_events()
- .expect("seller revision fixture should import");
- set_persisted_order_status(&runtime, order_id, "scheduled");
-
- assert!(
- runtime
- .publish_order_fulfillment_update(
- order_id,
- OrderFulfillmentAction::ReadyForPickup,
- )
- .expect("seller ready fulfillment should publish from revision parent")
- );
-
- assert_eq!(relay.event_count(), 0);
- let fulfillment_events =
- shared_order_events_by_kind(&paths, 3433, seller_pubkey.as_str());
- assert!(fulfillment_events.is_empty());
- assert_order_fulfillment_sdk_migration_receipt(
- &runtime,
- order_id,
- RadrootsOrderFulfillmentState::ReadyForPickup,
- AppSdkMigrationState::Enqueued,
- );
-
- cleanup_bootstrapped_runtime_paths(&paths);
- }
- }
-
- #[test]
- fn runtime_publishes_seller_order_fulfillment_delivered_when_coarse_status_lags() {
+ fn runtime_rejects_seller_order_revision_with_reducer_invalid_parent_evidence() {
let relay = ThreadedAckRelay::spawn();
let (runtime, paths, order_id, product_id, seller_pubkey, buyer_pubkey) =
- seller_order_decision_runtime("seller_order_fulfillment_delivery_status_lag", 6, 2);
+ seller_order_decision_runtime("seller_order_revision_invalid_parent", 6, 2);
install_direct_relay_sync_transport(&runtime, &relay);
let listing_key = super::d_tag_from_uuid(product_id.as_uuid());
let listing_addr = format!("30402:{seller_pubkey}:{listing_key}");
let request_event_id = shared_order_request_event_id(&paths, "seller-order-decision-1");
let request_event_id = request_event_id.as_str();
- let decision_event_id = append_signed_order_decision_record(
+ append_signed_order_decision_record(
&paths,
"seller-order-decision-1",
request_event_id,
@@ -16673,261 +15825,12 @@ mod tests {
seller_pubkey.as_str(),
2,
);
- let _ready_event_id = append_signed_order_fulfillment_record_with_status(
+ append_signed_order_revision_proposal_record_with_prev(
&paths,
"seller-order-decision-1",
+ "seller-order-decision-1-stale-revision",
+ request_event_id,
request_event_id,
- decision_event_id.as_str(),
- listing_addr.as_str(),
- buyer_pubkey.as_str(),
- seller_pubkey.as_str(),
- RadrootsOrderFulfillmentState::ReadyForPickup,
- );
- runtime
- .refresh_shared_local_events()
- .expect("seller ready fulfillment should import");
- assert_eq!(persisted_order_status(&runtime, order_id), "packed");
- set_persisted_order_status(&runtime, order_id, "scheduled");
-
- assert!(
- runtime
- .publish_order_fulfillment_update(order_id, OrderFulfillmentAction::Delivered)
- .expect("seller delivered fulfillment should publish from workflow evidence")
- );
-
- assert_eq!(persisted_order_status(&runtime, order_id), "scheduled");
- assert_eq!(relay.event_count(), 0);
- let fulfillment_events = shared_order_events_by_kind(&paths, 3433, seller_pubkey.as_str());
- assert_eq!(fulfillment_events.len(), 1);
- assert_order_fulfillment_sdk_migration_receipt(
- &runtime,
- order_id,
- RadrootsOrderFulfillmentState::Delivered,
- AppSdkMigrationState::Enqueued,
- );
-
- cleanup_bootstrapped_runtime_paths(&paths);
- }
-
- #[test]
- fn runtime_publishes_seller_order_fulfillment_delivered_without_ready_evidence() {
- for (label, latest_fulfillment) in [
- ("seller_order_fulfillment_delivery_missing_ready", None),
- (
- "seller_order_fulfillment_delivery_preparing",
- Some(RadrootsOrderFulfillmentState::Preparing),
- ),
- ] {
- let relay = ThreadedAckRelay::spawn();
- let (runtime, paths, order_id, product_id, seller_pubkey, buyer_pubkey) =
- seller_order_decision_runtime(label, 6, 2);
- install_direct_relay_sync_transport(&runtime, &relay);
- let listing_key = super::d_tag_from_uuid(product_id.as_uuid());
- let listing_addr = format!("30402:{seller_pubkey}:{listing_key}");
- let request_event_id = shared_order_request_event_id(&paths, "seller-order-decision-1");
- let request_event_id = request_event_id.as_str();
- let decision_event_id = append_signed_order_decision_record(
- &paths,
- "seller-order-decision-1",
- request_event_id,
- listing_addr.as_str(),
- buyer_pubkey.as_str(),
- seller_pubkey.as_str(),
- 2,
- );
- if let Some(status) = latest_fulfillment {
- append_signed_order_fulfillment_record_with_status(
- &paths,
- "seller-order-decision-1",
- request_event_id,
- decision_event_id.as_str(),
- listing_addr.as_str(),
- buyer_pubkey.as_str(),
- seller_pubkey.as_str(),
- status,
- );
- }
- runtime
- .refresh_shared_local_events()
- .expect("seller fulfillment fixture should import");
-
- assert!(
- runtime
- .publish_order_fulfillment_update(order_id, OrderFulfillmentAction::Delivered)
- .expect("seller delivered fulfillment should publish")
- );
-
- assert_eq!(persisted_order_status(&runtime, order_id), "scheduled");
- assert_eq!(relay.event_count(), 0);
- let fulfillment_events =
- shared_order_events_by_kind(&paths, 3433, seller_pubkey.as_str());
- assert_eq!(
- fulfillment_events.len(),
- usize::from(latest_fulfillment.is_some())
- );
- assert_order_fulfillment_sdk_migration_receipt(
- &runtime,
- order_id,
- RadrootsOrderFulfillmentState::Delivered,
- AppSdkMigrationState::Enqueued,
- );
- cleanup_bootstrapped_runtime_paths(&paths);
- }
- }
-
- #[test]
- fn runtime_rejects_seller_order_fulfillment_delivered_with_reducer_invalid_ready_evidence() {
- for label in [
- "seller_order_fulfillment_delivery_unchained_ready",
- "seller_order_fulfillment_delivery_forked_ready",
- ] {
- let relay = ThreadedAckRelay::spawn();
- let (runtime, paths, order_id, product_id, seller_pubkey, buyer_pubkey) =
- seller_order_decision_runtime(label, 6, 2);
- install_direct_relay_sync_transport(&runtime, &relay);
- let listing_key = super::d_tag_from_uuid(product_id.as_uuid());
- let listing_addr = format!("30402:{seller_pubkey}:{listing_key}");
- let request_event_id = shared_order_request_event_id(&paths, "seller-order-decision-1");
- let request_event_id = request_event_id.as_str();
- let decision_event_id = append_signed_order_decision_record(
- &paths,
- "seller-order-decision-1",
- request_event_id,
- listing_addr.as_str(),
- buyer_pubkey.as_str(),
- seller_pubkey.as_str(),
- 2,
- );
- if label.ends_with("unchained_ready") {
- append_signed_order_fulfillment_record_with_status_and_key(
- &paths,
- "seller-order-decision-1",
- "seller-order-decision-1-unchained-ready",
- request_event_id,
- request_event_id,
- listing_addr.as_str(),
- buyer_pubkey.as_str(),
- seller_pubkey.as_str(),
- RadrootsOrderFulfillmentState::ReadyForPickup,
- );
- } else {
- append_signed_order_fulfillment_record_with_status_and_key(
- &paths,
- "seller-order-decision-1",
- "seller-order-decision-1-forked-preparing",
- request_event_id,
- decision_event_id.as_str(),
- listing_addr.as_str(),
- buyer_pubkey.as_str(),
- seller_pubkey.as_str(),
- RadrootsOrderFulfillmentState::Preparing,
- );
- append_signed_order_fulfillment_record_with_status_and_key(
- &paths,
- "seller-order-decision-1",
- "seller-order-decision-1-forked-ready",
- request_event_id,
- decision_event_id.as_str(),
- listing_addr.as_str(),
- buyer_pubkey.as_str(),
- seller_pubkey.as_str(),
- RadrootsOrderFulfillmentState::ReadyForPickup,
- );
- }
-
- let error = runtime
- .publish_order_fulfillment_update(order_id, OrderFulfillmentAction::Delivered)
- .expect_err("seller delivered fulfillment should reject reducer-invalid evidence");
-
- assert_order_lifecycle_evidence_invalid(error);
- assert_eq!(relay.event_count(), 0);
- cleanup_bootstrapped_runtime_paths(&paths);
- }
- }
-
- #[test]
- fn runtime_rejects_seller_order_fulfillment_ready_with_invalid_terminal_evidence() {
- for label in [
- "seller_order_fulfillment_invalid_cancellation",
- "seller_order_fulfillment_invalid_receipt",
- ] {
- let relay = ThreadedAckRelay::spawn();
- let (runtime, paths, order_id, product_id, seller_pubkey, buyer_pubkey) =
- seller_order_decision_runtime(label, 6, 2);
- install_direct_relay_sync_transport(&runtime, &relay);
- let listing_key = super::d_tag_from_uuid(product_id.as_uuid());
- let listing_addr = format!("30402:{seller_pubkey}:{listing_key}");
- let request_event_id = shared_order_request_event_id(&paths, "seller-order-decision-1");
- let request_event_id = request_event_id.as_str();
- append_signed_order_decision_record(
- &paths,
- "seller-order-decision-1",
- request_event_id,
- listing_addr.as_str(),
- buyer_pubkey.as_str(),
- seller_pubkey.as_str(),
- 2,
- );
- if label.ends_with("invalid_cancellation") {
- append_signed_order_cancellation_record_with_prev(
- &paths,
- "seller-order-decision-1",
- "seller-order-decision-1-invalid-cancellation",
- request_event_id,
- request_event_id,
- listing_addr.as_str(),
- buyer_pubkey.as_str(),
- seller_pubkey.as_str(),
- );
- } else {
- append_signed_order_receipt_record_with_prev(
- &paths,
- "seller-order-decision-1",
- "seller-order-decision-1-invalid-receipt",
- request_event_id,
- request_event_id,
- listing_addr.as_str(),
- buyer_pubkey.as_str(),
- seller_pubkey.as_str(),
- true,
- );
- }
-
- let error = runtime
- .publish_order_fulfillment_update(order_id, OrderFulfillmentAction::ReadyForPickup)
- .expect_err("seller ready fulfillment should reject invalid terminal evidence");
-
- assert_order_lifecycle_evidence_invalid(error);
- assert_eq!(relay.event_count(), 0);
- cleanup_bootstrapped_runtime_paths(&paths);
- }
- }
-
- #[test]
- fn runtime_rejects_seller_order_revision_with_reducer_invalid_parent_evidence() {
- let relay = ThreadedAckRelay::spawn();
- let (runtime, paths, order_id, product_id, seller_pubkey, buyer_pubkey) =
- seller_order_decision_runtime("seller_order_revision_invalid_parent", 6, 2);
- install_direct_relay_sync_transport(&runtime, &relay);
- let listing_key = super::d_tag_from_uuid(product_id.as_uuid());
- let listing_addr = format!("30402:{seller_pubkey}:{listing_key}");
- let request_event_id = shared_order_request_event_id(&paths, "seller-order-decision-1");
- let request_event_id = request_event_id.as_str();
- append_signed_order_decision_record(
- &paths,
- "seller-order-decision-1",
- request_event_id,
- listing_addr.as_str(),
- buyer_pubkey.as_str(),
- seller_pubkey.as_str(),
- 2,
- );
- append_signed_order_revision_proposal_record_with_prev(
- &paths,
- "seller-order-decision-1",
- "seller-order-decision-1-stale-revision",
- request_event_id,
- request_event_id,
listing_addr.as_str(),
buyer_pubkey.as_str(),
seller_pubkey.as_str(),
@@ -16948,200 +15851,6 @@ mod tests {
}
#[test]
- fn runtime_rejects_seller_order_revision_after_recorded_or_settled_payment_evidence() {
- for (label, settlement) in [
- ("recorded", None),
- ("settled", Some(RadrootsOrderSettlementOutcome::Accepted)),
- ] {
- let relay = ThreadedAckRelay::spawn();
- let runtime_label = format!("seller_order_revision_payment_{label}");
- let (runtime, paths, order_id, product_id, seller_pubkey, buyer_pubkey) =
- seller_order_decision_runtime(runtime_label.as_str(), 6, 2);
- install_direct_relay_sync_transport(&runtime, &relay);
- let listing_key = super::d_tag_from_uuid(product_id.as_uuid());
- let listing_addr = format!("30402:{seller_pubkey}:{listing_key}");
- let request_event_id = shared_order_request_event_id(&paths, "seller-order-decision-1");
- let request_event_id = request_event_id.as_str();
- let decision_event_id = append_signed_order_decision_record(
- &paths,
- "seller-order-decision-1",
- request_event_id,
- listing_addr.as_str(),
- buyer_pubkey.as_str(),
- seller_pubkey.as_str(),
- 2,
- );
- let payment_event_id = append_signed_payment_record(
- &paths,
- "seller-order-decision-1",
- format!("seller-order-revision-payment-{label}").as_str(),
- request_event_id,
- decision_event_id.as_str(),
- listing_addr.as_str(),
- buyer_pubkey.as_str(),
- seller_pubkey.as_str(),
- 2,
- );
- if let Some(decision) = settlement {
- append_signed_settlement_decision_record(
- &paths,
- "seller-order-decision-1",
- format!("seller-order-revision-k3436-{label}").as_str(),
- request_event_id,
- decision_event_id.as_str(),
- payment_event_id.as_str(),
- listing_addr.as_str(),
- buyer_pubkey.as_str(),
- seller_pubkey.as_str(),
- 2,
- decision,
- );
- }
- runtime
- .refresh_shared_local_events()
- .expect("seller payment evidence should import");
- set_persisted_order_status(&runtime, order_id, "scheduled");
-
- let error = runtime
- .publish_order_revision_proposal(
- order_id,
- revision_test_order_items(),
- revision_test_order_economics(),
- "harvest count updated",
- )
- .expect_err("seller revision proposal should reject payment evidence");
-
- assert!(matches!(
- error,
- AppSqliteError::InvalidProjection {
- reason: "seller order revision requires no recorded or settled payment"
- }
- ));
- assert_eq!(relay.event_count(), 0);
- cleanup_bootstrapped_runtime_paths(&paths);
- }
- }
-
- #[test]
- fn runtime_rejects_seller_order_revision_after_rejected_settlement_evidence() {
- let relay = ThreadedAckRelay::spawn();
- let (runtime, paths, order_id, product_id, seller_pubkey, buyer_pubkey) =
- seller_order_decision_runtime("seller_order_revision_rejected_payment", 6, 2);
- install_direct_relay_sync_transport(&runtime, &relay);
- let listing_key = super::d_tag_from_uuid(product_id.as_uuid());
- let listing_addr = format!("30402:{seller_pubkey}:{listing_key}");
- let request_event_id = shared_order_request_event_id(&paths, "seller-order-decision-1");
- let request_event_id = request_event_id.as_str();
- let decision_event_id = append_signed_order_decision_record(
- &paths,
- "seller-order-decision-1",
- request_event_id,
- listing_addr.as_str(),
- buyer_pubkey.as_str(),
- seller_pubkey.as_str(),
- 2,
- );
- let payment_event_id = append_signed_payment_record(
- &paths,
- "seller-order-decision-1",
- "seller-order-revision-payment-rejected",
- request_event_id,
- decision_event_id.as_str(),
- listing_addr.as_str(),
- buyer_pubkey.as_str(),
- seller_pubkey.as_str(),
- 2,
- );
- append_signed_settlement_decision_record(
- &paths,
- "seller-order-decision-1",
- "seller-order-revision-k3436-rejected",
- request_event_id,
- decision_event_id.as_str(),
- payment_event_id.as_str(),
- listing_addr.as_str(),
- buyer_pubkey.as_str(),
- seller_pubkey.as_str(),
- 2,
- RadrootsOrderSettlementOutcome::Rejected,
- );
- runtime
- .refresh_shared_local_events()
- .expect("seller rejected payment evidence should import");
- set_persisted_order_status(&runtime, order_id, "scheduled");
-
- let error = runtime
- .publish_order_revision_proposal(
- order_id,
- revision_test_order_items(),
- revision_test_order_economics(),
- "harvest count updated",
- )
- .expect_err("seller revision proposal should reject rejected 3436 payment evidence");
-
- assert!(matches!(
- error,
- AppSqliteError::InvalidProjection {
- reason: "seller order revision requires no recorded or settled payment"
- }
- ));
- assert_eq!(relay.event_count(), 0);
- let revision_events = shared_order_events_by_kind(&paths, 3424, seller_pubkey.as_str());
- assert!(revision_events.is_empty());
- cleanup_bootstrapped_runtime_paths(&paths);
- }
-
- #[test]
- fn runtime_rejects_seller_order_revision_with_invalid_payment_evidence() {
- let relay = ThreadedAckRelay::spawn();
- let (runtime, paths, order_id, product_id, seller_pubkey, buyer_pubkey) =
- seller_order_decision_runtime("seller_order_revision_invalid_payment", 6, 2);
- install_direct_relay_sync_transport(&runtime, &relay);
- let listing_key = super::d_tag_from_uuid(product_id.as_uuid());
- let listing_addr = format!("30402:{seller_pubkey}:{listing_key}");
- let request_event_id = shared_order_request_event_id(&paths, "seller-order-decision-1");
- let request_event_id = request_event_id.as_str();
- let decision_event_id = append_signed_order_decision_record(
- &paths,
- "seller-order-decision-1",
- request_event_id,
- listing_addr.as_str(),
- buyer_pubkey.as_str(),
- seller_pubkey.as_str(),
- 2,
- );
- append_signed_payment_record_with_prev(
- &paths,
- "seller-order-decision-1",
- "seller-order-revision-invalid-payment",
- request_event_id,
- request_event_id,
- decision_event_id.as_str(),
- listing_addr.as_str(),
- buyer_pubkey.as_str(),
- seller_pubkey.as_str(),
- 2,
- );
- runtime
- .refresh_shared_local_events()
- .expect("seller invalid payment evidence should import");
- set_persisted_order_status(&runtime, order_id, "scheduled");
-
- let error = runtime
- .publish_order_revision_proposal(
- order_id,
- revision_test_order_items(),
- revision_test_order_economics(),
- "harvest count updated",
- )
- .expect_err("seller revision proposal should reject invalid payment evidence");
-
- assert_order_lifecycle_evidence_invalid(error);
- assert_eq!(relay.event_count(), 0);
- cleanup_bootstrapped_runtime_paths(&paths);
- }
-
- #[test]
fn runtime_places_supported_buyer_order_into_shared_local_events() {
let (runtime, paths) = bootstrapped_runtime("buyer_order_local_event");
assert!(
@@ -17299,8 +16008,6 @@ mod tests {
.as_ref()
.expect("order local work payload");
assert_eq!(payload["support_status"]["state"], "supported");
- assert_eq!(payload["payment_display"]["state"], "not_recorded");
- assert_eq!(payload["payment_display"]["allows_payment_action"], false);
assert_eq!(payload["currentness"]["current"], true);
assert_eq!(payload["document"]["kind"], "order_draft_v1");
assert_eq!(
@@ -17673,7 +16380,7 @@ mod tests {
#[test]
fn runtime_opens_linked_buyer_order_detail_from_selected_account_nostr_scope() {
- let fixture = linked_buyer_lifecycle_runtime("linked_buyer_order_open", false);
+ let fixture = linked_buyer_lifecycle_runtime("linked_buyer_order_open");
let report = fixture
.runtime
.refresh_shared_local_events()
@@ -17716,7 +16423,7 @@ mod tests {
#[test]
fn runtime_publishes_linked_buyer_cancellation_from_selected_account_nostr_scope() {
let relay = ThreadedAckRelay::spawn();
- let fixture = linked_buyer_lifecycle_runtime("linked_buyer_order_cancel", false);
+ let fixture = linked_buyer_lifecycle_runtime("linked_buyer_order_cancel");
install_direct_relay_sync_transport(&fixture.runtime, &relay);
fixture
.runtime
@@ -17754,348 +16461,56 @@ mod tests {
}
#[test]
- fn runtime_rejects_linked_buyer_cancellation_after_recorded_or_settled_payment_evidence() {
- for (label, settlement) in [
- ("recorded", None),
- ("settled", Some(RadrootsOrderSettlementOutcome::Accepted)),
+ fn runtime_publishes_linked_buyer_cancellation_from_revision_parent() {
+ for (label, revision_decision) in [
+ ("accepted", RadrootsOrderRevisionOutcome::Accepted),
+ (
+ "declined",
+ RadrootsOrderRevisionOutcome::Declined {
+ reason: "keep original order".to_owned(),
+ },
+ ),
] {
let relay = ThreadedAckRelay::spawn();
- let fixture_label = format!("linked_buyer_order_cancel_payment_{label}");
- let fixture = linked_buyer_lifecycle_runtime(fixture_label.as_str(), false);
- install_direct_relay_sync_transport(&fixture.runtime, &relay);
- let payment_event_id = append_signed_payment_record(
+ let fixture_label = format!("linked_buyer_order_cancel_revision_{label}");
+ let fixture = linked_buyer_lifecycle_runtime(fixture_label.as_str());
+ let proposal_key = format!("linked-buyer-order-cancel-revision-{label}-proposal");
+ let proposal_event_id = append_signed_order_revision_proposal_record_with_prev(
&fixture.paths,
fixture.trade_order_id.as_str(),
- format!("linked-buyer-cancel-payment-{label}").as_str(),
+ proposal_key.as_str(),
fixture.request_event_id.as_str(),
fixture.decision_event_id.as_str(),
fixture.listing_addr.as_str(),
fixture.buyer_pubkey.as_str(),
fixture.seller_pubkey.as_str(),
- 2,
);
- if let Some(decision) = settlement {
- append_signed_settlement_decision_record(
+ let revision_id = format!("revision-{proposal_key}");
+ let _revision_decision_event_id =
+ append_signed_order_revision_decision_record_with_prev(
&fixture.paths,
fixture.trade_order_id.as_str(),
- format!("linked-buyer-cancel-k3436-{label}").as_str(),
+ format!("linked-buyer-order-cancel-revision-{label}-decision").as_str(),
fixture.request_event_id.as_str(),
- fixture.decision_event_id.as_str(),
- payment_event_id.as_str(),
+ proposal_event_id.as_str(),
+ revision_id.as_str(),
fixture.listing_addr.as_str(),
fixture.buyer_pubkey.as_str(),
fixture.seller_pubkey.as_str(),
- 2,
- decision,
+ revision_decision,
);
- }
+ install_direct_relay_sync_transport(&fixture.runtime, &relay);
fixture
.runtime
.refresh_shared_local_events()
- .expect("linked buyer payment evidence should import");
+ .expect("linked buyer revision events should import");
assert!(
fixture
.runtime
.open_personal_order_detail(fixture.order_id)
.expect("linked buyer order detail should open")
);
-
- let error = fixture
- .runtime
- .publish_buyer_order_cancel(fixture.order_id)
- .expect_err("linked buyer cancellation should reject payment evidence");
-
- assert!(matches!(
- error,
- AppSqliteError::InvalidProjection {
- reason: "buyer order cancellation requires no recorded or settled payment"
- }
- ));
- assert_eq!(relay.event_count(), 0);
- cleanup_bootstrapped_runtime_paths(&fixture.paths);
- }
- }
-
- #[test]
- fn runtime_rejects_linked_buyer_cancellation_after_rejected_settlement_evidence() {
- let relay = ThreadedAckRelay::spawn();
- let fixture =
- linked_buyer_lifecycle_runtime("linked_buyer_order_cancel_rejected_payment", false);
- install_direct_relay_sync_transport(&fixture.runtime, &relay);
- let payment_event_id = append_signed_payment_record(
- &fixture.paths,
- fixture.trade_order_id.as_str(),
- "linked-buyer-cancel-payment-rejected",
- fixture.request_event_id.as_str(),
- fixture.decision_event_id.as_str(),
- fixture.listing_addr.as_str(),
- fixture.buyer_pubkey.as_str(),
- fixture.seller_pubkey.as_str(),
- 2,
- );
- append_signed_settlement_decision_record(
- &fixture.paths,
- fixture.trade_order_id.as_str(),
- "linked-buyer-cancel-k3436-rejected",
- fixture.request_event_id.as_str(),
- fixture.decision_event_id.as_str(),
- payment_event_id.as_str(),
- fixture.listing_addr.as_str(),
- fixture.buyer_pubkey.as_str(),
- fixture.seller_pubkey.as_str(),
- 2,
- RadrootsOrderSettlementOutcome::Rejected,
- );
- fixture
- .runtime
- .refresh_shared_local_events()
- .expect("linked buyer rejected payment evidence should import");
- assert!(
- fixture
- .runtime
- .open_personal_order_detail(fixture.order_id)
- .expect("linked buyer order detail should open")
- );
-
- let error = fixture
- .runtime
- .publish_buyer_order_cancel(fixture.order_id)
- .expect_err("linked buyer cancellation should reject rejected 3436 payment evidence");
-
- assert!(matches!(
- error,
- AppSqliteError::InvalidProjection {
- reason: "buyer order cancellation requires no recorded or settled payment"
- }
- ));
- assert_eq!(relay.event_count(), 0);
- let cancellation_events =
- shared_order_events_by_kind(&fixture.paths, 3432, fixture.buyer_pubkey.as_str());
- assert!(cancellation_events.is_empty());
- cleanup_bootstrapped_runtime_paths(&fixture.paths);
- }
-
- #[test]
- fn runtime_rejects_linked_buyer_cancellation_with_invalid_payment_evidence() {
- let relay = ThreadedAckRelay::spawn();
- let fixture =
- linked_buyer_lifecycle_runtime("linked_buyer_order_cancel_invalid_payment", false);
- install_direct_relay_sync_transport(&fixture.runtime, &relay);
- append_signed_payment_record_with_prev(
- &fixture.paths,
- fixture.trade_order_id.as_str(),
- "linked-buyer-cancel-invalid-payment",
- fixture.request_event_id.as_str(),
- fixture.request_event_id.as_str(),
- fixture.decision_event_id.as_str(),
- fixture.listing_addr.as_str(),
- fixture.buyer_pubkey.as_str(),
- fixture.seller_pubkey.as_str(),
- 2,
- );
- fixture
- .runtime
- .refresh_shared_local_events()
- .expect("linked buyer invalid payment evidence should import");
- assert!(
- fixture
- .runtime
- .open_personal_order_detail(fixture.order_id)
- .expect("linked buyer order detail should open")
- );
-
- let error = fixture
- .runtime
- .publish_buyer_order_cancel(fixture.order_id)
- .expect_err("linked buyer cancellation should reject invalid payment evidence");
-
- assert_order_lifecycle_evidence_invalid(error);
- assert_eq!(relay.event_count(), 0);
- cleanup_bootstrapped_runtime_paths(&fixture.paths);
- }
-
- #[test]
- fn runtime_rejects_linked_buyer_cancellation_after_relay_payment_evidence() {
- let relay = ThreadedAckRelay::spawn();
- let fixture =
- linked_buyer_lifecycle_runtime("linked_buyer_order_cancel_relay_payment", false);
- configure_runtime_relay_ingest(&fixture.runtime, &relay);
- fixture
- .runtime
- .refresh_shared_local_events()
- .expect("linked buyer local events should import");
- assert!(
- fixture
- .runtime
- .open_personal_order_detail(fixture.order_id)
- .expect("linked buyer order detail should open")
- );
- let buyer_identity = selected_account_signing_identity(&fixture.runtime);
- let payment_event = signed_payment_recorded_relay_event(
- &buyer_identity,
- fixture.trade_order_id.as_str(),
- fixture.request_event_id.as_str(),
- fixture.decision_event_id.as_str(),
- fixture.listing_addr.as_str(),
- fixture.buyer_pubkey.as_str(),
- fixture.seller_pubkey.as_str(),
- 2,
- );
- let payment_event_id = payment_event.id.to_hex();
- relay.push_event(&payment_event);
-
- let error = fixture
- .runtime
- .publish_buyer_order_cancel(fixture.order_id)
- .expect_err("linked buyer cancellation should reject relay payment evidence");
-
- assert!(matches!(
- error,
- AppSqliteError::InvalidProjection {
- reason: "buyer order cancellation requires no recorded or settled payment"
- }
- ));
- let payment_events = fixture
- .runtime
- .lock_state()
- .sqlite_store
- .as_ref()
- .expect("sqlite store")
- .load_local_interop_signed_events_by_kind(3435)
- .expect("relay payment evidence should load from local interop");
- assert!(
- payment_events
- .iter()
- .any(|event| event.id == payment_event_id)
- );
- assert_eq!(relay.event_count(), 1);
- cleanup_bootstrapped_runtime_paths(&fixture.paths);
- }
-
- #[test]
- fn runtime_rejects_linked_buyer_cancellation_after_relay_settlement_evidence() {
- let relay = ThreadedAckRelay::spawn();
- let seller_identity = RadrootsIdentity::generate();
- let seller_pubkey = seller_identity.public_key_hex();
- let fixture = linked_buyer_lifecycle_runtime_with_seller_pubkey(
- "linked_buyer_order_cancel_relay_k3436",
- false,
- seller_pubkey.as_str(),
- );
- configure_runtime_relay_ingest(&fixture.runtime, &relay);
- fixture
- .runtime
- .refresh_shared_local_events()
- .expect("linked buyer local events should import");
- assert!(
- fixture
- .runtime
- .open_personal_order_detail(fixture.order_id)
- .expect("linked buyer order detail should open")
- );
- let buyer_identity = selected_account_signing_identity(&fixture.runtime);
- let payment_event = signed_payment_recorded_relay_event(
- &buyer_identity,
- fixture.trade_order_id.as_str(),
- fixture.request_event_id.as_str(),
- fixture.decision_event_id.as_str(),
- fixture.listing_addr.as_str(),
- fixture.buyer_pubkey.as_str(),
- fixture.seller_pubkey.as_str(),
- 2,
- );
- let payment_event_id = payment_event.id.to_hex();
- let k3436_event = signed_settlement_decision_relay_event(
- &seller_identity,
- fixture.trade_order_id.as_str(),
- fixture.request_event_id.as_str(),
- fixture.decision_event_id.as_str(),
- payment_event_id.as_str(),
- fixture.listing_addr.as_str(),
- fixture.buyer_pubkey.as_str(),
- fixture.seller_pubkey.as_str(),
- 2,
- RadrootsOrderSettlementOutcome::Accepted,
- );
- let k3436_event_id = k3436_event.id.to_hex();
- relay.push_event(&payment_event);
- relay.push_event(&k3436_event);
-
- let error = fixture
- .runtime
- .publish_buyer_order_cancel(fixture.order_id)
- .expect_err("linked buyer cancellation should reject relay k3436 evidence");
-
- assert!(matches!(
- error,
- AppSqliteError::InvalidProjection {
- reason: "buyer order cancellation requires no recorded or settled payment"
- }
- ));
- let k3436_events = fixture
- .runtime
- .lock_state()
- .sqlite_store
- .as_ref()
- .expect("sqlite store")
- .load_local_interop_signed_events_by_kind(3436)
- .expect("relay k3436 evidence should load from local interop");
- assert!(k3436_events.iter().any(|event| event.id == k3436_event_id));
- assert_eq!(relay.event_count(), 2);
- cleanup_bootstrapped_runtime_paths(&fixture.paths);
- }
-
- #[test]
- fn runtime_publishes_linked_buyer_cancellation_from_revision_parent() {
- for (label, revision_decision) in [
- ("accepted", RadrootsOrderRevisionOutcome::Accepted),
- (
- "declined",
- RadrootsOrderRevisionOutcome::Declined {
- reason: "keep original order".to_owned(),
- },
- ),
- ] {
- let relay = ThreadedAckRelay::spawn();
- let fixture_label = format!("linked_buyer_order_cancel_revision_{label}");
- let fixture = linked_buyer_lifecycle_runtime(fixture_label.as_str(), false);
- let proposal_key = format!("linked-buyer-order-cancel-revision-{label}-proposal");
- let proposal_event_id = append_signed_order_revision_proposal_record_with_prev(
- &fixture.paths,
- fixture.trade_order_id.as_str(),
- proposal_key.as_str(),
- fixture.request_event_id.as_str(),
- fixture.decision_event_id.as_str(),
- fixture.listing_addr.as_str(),
- fixture.buyer_pubkey.as_str(),
- fixture.seller_pubkey.as_str(),
- );
- let revision_id = format!("revision-{proposal_key}");
- let _revision_decision_event_id =
- append_signed_order_revision_decision_record_with_prev(
- &fixture.paths,
- fixture.trade_order_id.as_str(),
- format!("linked-buyer-order-cancel-revision-{label}-decision").as_str(),
- fixture.request_event_id.as_str(),
- proposal_event_id.as_str(),
- revision_id.as_str(),
- fixture.listing_addr.as_str(),
- fixture.buyer_pubkey.as_str(),
- fixture.seller_pubkey.as_str(),
- revision_decision,
- );
- install_direct_relay_sync_transport(&fixture.runtime, &relay);
- fixture
- .runtime
- .refresh_shared_local_events()
- .expect("linked buyer revision events should import");
- assert!(
- fixture
- .runtime
- .open_personal_order_detail(fixture.order_id)
- .expect("linked buyer order detail should open")
- );
- set_persisted_order_status(&fixture.runtime, fixture.order_id, "scheduled");
+ set_persisted_order_status(&fixture.runtime, fixture.order_id, "scheduled");
assert!(
fixture
@@ -18119,170 +16534,9 @@ mod tests {
}
#[test]
- fn runtime_publishes_linked_buyer_receipt_from_selected_account_nostr_scope() {
- let relay = ThreadedAckRelay::spawn();
- let fixture = linked_buyer_lifecycle_runtime("linked_buyer_order_receipt", true);
- let _fulfillment_event_id = fixture
- .fulfillment_event_id
- .as_deref()
- .expect("ready fixture should include fulfillment event")
- .to_owned();
- install_direct_relay_sync_transport(&fixture.runtime, &relay);
- fixture
- .runtime
- .refresh_shared_local_events()
- .expect("linked buyer local events should import");
- assert!(
- fixture
- .runtime
- .open_personal_order_detail(fixture.order_id)
- .expect("linked ready buyer order detail should open")
- );
- assert_eq!(
- fixture
- .runtime
- .summary()
- .personal_projection
- .orders
- .detail
- .as_ref()
- .expect("linked ready buyer detail")
- .status,
- BuyerOrderStatus::Ready
- );
-
- assert!(
- fixture
- .runtime
- .publish_buyer_order_receipt(fixture.order_id, AppOrderReceiptOutcome::Received)
- .expect("linked buyer receipt should publish")
- );
-
- assert_eq!(
- persisted_order_status(&fixture.runtime, fixture.order_id),
- "packed"
- );
- assert_eq!(relay.event_count(), 0);
- let receipt_events =
- shared_order_events_by_kind(&fixture.paths, 3434, fixture.buyer_pubkey.as_str());
- assert!(receipt_events.is_empty());
- assert_order_receipt_sdk_migration_receipt(
- &fixture.runtime,
- fixture.order_id,
- AppSdkMigrationState::Enqueued,
- );
-
- cleanup_bootstrapped_runtime_paths(&fixture.paths);
- }
-
- #[test]
- fn runtime_publishes_linked_buyer_receipt_after_direct_delivered_fulfillment() {
- let relay = ThreadedAckRelay::spawn();
- let fixture = linked_buyer_lifecycle_runtime("linked_buyer_order_receipt_delivered", false);
- let _fulfillment_event_id = append_signed_order_fulfillment_record_with_status(
- &fixture.paths,
- fixture.trade_order_id.as_str(),
- fixture.request_event_id.as_str(),
- fixture.decision_event_id.as_str(),
- fixture.listing_addr.as_str(),
- fixture.buyer_pubkey.as_str(),
- fixture.seller_pubkey.as_str(),
- RadrootsOrderFulfillmentState::Delivered,
- );
- install_direct_relay_sync_transport(&fixture.runtime, &relay);
- fixture
- .runtime
- .refresh_shared_local_events()
- .expect("linked buyer delivered local events should import");
- assert!(
- fixture
- .runtime
- .open_personal_order_detail(fixture.order_id)
- .expect("linked delivered buyer order detail should open")
- );
-
- assert!(
- fixture
- .runtime
- .publish_buyer_order_receipt(fixture.order_id, AppOrderReceiptOutcome::Received)
- .expect("linked delivered buyer receipt should publish")
- );
-
- assert_eq!(
- persisted_order_status(&fixture.runtime, fixture.order_id),
- "packed"
- );
- assert_eq!(relay.event_count(), 0);
- let receipt_events =
- shared_order_events_by_kind(&fixture.paths, 3434, fixture.buyer_pubkey.as_str());
- assert!(receipt_events.is_empty());
- assert_order_receipt_sdk_migration_receipt(
- &fixture.runtime,
- fixture.order_id,
- AppSdkMigrationState::Enqueued,
- );
-
- cleanup_bootstrapped_runtime_paths(&fixture.paths);
- }
-
- #[test]
- fn runtime_publishes_linked_buyer_issue_receipt_from_selected_account_nostr_scope() {
- let relay = ThreadedAckRelay::spawn();
- let fixture = linked_buyer_lifecycle_runtime("linked_buyer_order_issue_receipt", true);
- install_direct_relay_sync_transport(&fixture.runtime, &relay);
- fixture
- .runtime
- .refresh_shared_local_events()
- .expect("linked buyer local events should import");
- assert!(
- fixture
- .runtime
- .open_personal_order_detail(fixture.order_id)
- .expect("linked ready buyer order detail should open")
- );
-
- assert!(
- fixture
- .runtime
- .publish_buyer_order_receipt(
- fixture.order_id,
- AppOrderReceiptOutcome::issue("items need review")
- .expect("issue receipt text should be accepted"),
- )
- .expect("linked buyer issue receipt should publish")
- );
-
- assert_eq!(
- persisted_order_status(&fixture.runtime, fixture.order_id),
- "packed"
- );
- assert_eq!(relay.event_count(), 0);
- let receipt_events =
- shared_order_events_by_kind(&fixture.paths, 3434, fixture.buyer_pubkey.as_str());
- assert!(receipt_events.is_empty());
- let buyer_detail = fixture
- .runtime
- .summary()
- .personal_projection
- .orders
- .detail
- .as_ref()
- .expect("linked buyer issue receipt detail")
- .clone();
- assert_eq!(buyer_detail.status, BuyerOrderStatus::Ready);
- assert_order_receipt_sdk_migration_receipt(
- &fixture.runtime,
- fixture.order_id,
- AppSdkMigrationState::Enqueued,
- );
-
- cleanup_bootstrapped_runtime_paths(&fixture.paths);
- }
-
- #[test]
fn runtime_rejects_linked_buyer_cancellation_with_reducer_invalid_evidence() {
let relay = ThreadedAckRelay::spawn();
- let fixture = linked_buyer_lifecycle_runtime("linked_buyer_order_cancel_invalid", false);
+ let fixture = linked_buyer_lifecycle_runtime("linked_buyer_order_cancel_invalid");
install_direct_relay_sync_transport(&fixture.runtime, &relay);
fixture
.runtime
@@ -18319,58 +16573,8 @@ mod tests {
.runtime
.publish_buyer_order_cancel(fixture.order_id)
.expect_err("linked buyer cancellation should reject reducer-invalid evidence");
-
- assert_order_lifecycle_evidence_invalid(error);
- assert_eq!(relay.event_count(), 0);
- cleanup_bootstrapped_runtime_paths(&fixture.paths);
- }
-
- #[test]
- fn runtime_rejects_linked_buyer_receipt_with_reducer_invalid_fulfillment_evidence() {
- let relay = ThreadedAckRelay::spawn();
- let fixture = linked_buyer_lifecycle_runtime("linked_buyer_order_receipt_invalid", true);
- install_direct_relay_sync_transport(&fixture.runtime, &relay);
- fixture
- .runtime
- .refresh_shared_local_events()
- .expect("linked buyer local events should import");
- assert!(
- fixture
- .runtime
- .open_personal_order_detail(fixture.order_id)
- .expect("linked buyer order detail should open")
- );
- append_signed_order_fulfillment_record_with_status_and_key(
- &fixture.paths,
- fixture.trade_order_id.as_str(),
- "linked-buyer-order-receipt-forked-ready",
- fixture.request_event_id.as_str(),
- fixture.decision_event_id.as_str(),
- fixture.listing_addr.as_str(),
- fixture.buyer_pubkey.as_str(),
- fixture.seller_pubkey.as_str(),
- RadrootsOrderFulfillmentState::ReadyForPickup,
- );
- let resolver_error = {
- let state = fixture.runtime.lock_state();
- let request = state
- .resolve_seller_order_request_evidence(fixture.order_id)
- .expect("linked buyer request evidence should resolve");
- state
- .resolve_order_lifecycle_evidence(&request)
- .expect_err("linked buyer receipt evidence should be reducer-invalid")
- };
- assert_order_lifecycle_evidence_invalid(resolver_error);
-
- let error = fixture
- .runtime
- .publish_buyer_order_receipt(fixture.order_id, AppOrderReceiptOutcome::Received)
- .expect_err("linked buyer receipt should reject reducer-invalid fulfillment evidence");
-
- assert!(
- matches!(error, AppSqliteError::InvalidProjection { .. }),
- "{error:?}"
- );
+
+ assert_order_lifecycle_evidence_invalid(error);
assert_eq!(relay.event_count(), 0);
cleanup_bootstrapped_runtime_paths(&fixture.paths);
}
@@ -18378,7 +16582,7 @@ mod tests {
#[test]
fn runtime_publishes_linked_buyer_revision_decision_from_reducer_valid_parent() {
let relay = ThreadedAckRelay::spawn();
- let fixture = linked_buyer_lifecycle_runtime("linked_buyer_order_revision", false);
+ let fixture = linked_buyer_lifecycle_runtime("linked_buyer_order_revision");
let proposal_key = "linked-buyer-order-revision-proposal";
let _proposal_event_id = append_signed_order_revision_proposal_record_with_prev(
&fixture.paths,
@@ -21786,26 +19990,17 @@ mod tests {
trade_order_id: String,
request_event_id: String,
decision_event_id: String,
- fulfillment_event_id: Option<String>,
listing_addr: String,
buyer_pubkey: String,
seller_pubkey: String,
}
- fn linked_buyer_lifecycle_runtime(
- label: &str,
- include_ready_fulfillment: bool,
- ) -> LinkedBuyerLifecycleFixture {
- linked_buyer_lifecycle_runtime_with_seller_pubkey(
- label,
- include_ready_fulfillment,
- SDK_TEST_SELLER_PUBLIC_KEY_HEX,
- )
+ fn linked_buyer_lifecycle_runtime(label: &str) -> LinkedBuyerLifecycleFixture {
+ linked_buyer_lifecycle_runtime_with_seller_pubkey(label, SDK_TEST_SELLER_PUBLIC_KEY_HEX)
}
fn linked_buyer_lifecycle_runtime_with_seller_pubkey(
label: &str,
- include_ready_fulfillment: bool,
seller_pubkey: &str,
) -> LinkedBuyerLifecycleFixture {
let (runtime, paths) = bootstrapped_runtime(label);
@@ -21873,20 +20068,6 @@ mod tests {
seller_pubkey,
2,
);
- let fulfillment_event_id = if include_ready_fulfillment {
- Some(append_signed_order_fulfillment_record(
- &paths,
- trade_order_id.as_str(),
- request_event_id.as_str(),
- decision_event_id.as_str(),
- listing_addr.as_str(),
- buyer_pubkey.as_str(),
- seller_pubkey,
- ))
- } else {
- None
- };
-
LinkedBuyerLifecycleFixture {
runtime,
paths,
@@ -21894,7 +20075,6 @@ mod tests {
trade_order_id,
request_event_id,
decision_event_id,
- fulfillment_event_id,
listing_addr,
buyer_pubkey,
seller_pubkey: seller_pubkey.to_owned(),
@@ -22468,320 +20648,6 @@ mod tests {
)
}
- fn append_signed_payment_record(
- paths: &AppDesktopRuntimePaths,
- trade_order_id: &str,
- event_key: &str,
- request_event_id: &str,
- agreement_event_id: &str,
- listing_addr: &str,
- buyer_pubkey: &str,
- seller_pubkey: &str,
- order_quantity: u32,
- ) -> String {
- append_signed_payment_record_with_prev(
- paths,
- trade_order_id,
- event_key,
- request_event_id,
- agreement_event_id,
- agreement_event_id,
- listing_addr,
- buyer_pubkey,
- seller_pubkey,
- order_quantity,
- )
- }
-
- fn append_signed_payment_record_with_prev(
- paths: &AppDesktopRuntimePaths,
- trade_order_id: &str,
- event_key: &str,
- request_event_id: &str,
- prev_event_id: &str,
- agreement_event_id: &str,
- listing_addr: &str,
- buyer_pubkey: &str,
- seller_pubkey: &str,
- order_quantity: u32,
- ) -> String {
- let economics = signed_order_request_economics(trade_order_id, order_quantity);
- let request_event_id = test_event_id(request_event_id);
- let prev_event_id = test_event_id(prev_event_id);
- let agreement_event_id = test_event_id(agreement_event_id);
- let payload = RadrootsOrderPaymentRecord {
- order_id: test_order_id(trade_order_id),
- listing_addr: test_listing_addr(listing_addr),
- buyer_pubkey: test_pubkey(buyer_pubkey),
- seller_pubkey: test_pubkey(seller_pubkey),
- root_event_id: request_event_id.clone(),
- previous_event_id: prev_event_id.clone(),
- agreement_event_id,
- quote_id: economics.quote_id.clone(),
- quote_version: economics.quote_version,
- economics_digest: test_economics_digest(
- radroots_order_economics_digest(&economics).expect("payment economics digest"),
- ),
- amount: economics.total.amount,
- currency: economics.total.currency,
- method: RadrootsOrderPaymentMethod::ManualTransfer,
- reference: Some(format!("memo-{event_key}")),
- paid_at: Some(1_774_000_050),
- };
- let parts = order_payment_record_event_build(&request_event_id, &prev_event_id, &payload)
- .expect("payment recorded draft should build");
- let record_id = format!("app:signed_event:payment:{event_key}");
- append_trade_signed_event_record(
- paths,
- record_id.as_str(),
- buyer_pubkey,
- listing_addr,
- parts,
- )
- }
-
- fn append_signed_settlement_decision_record(
- paths: &AppDesktopRuntimePaths,
- trade_order_id: &str,
- event_key: &str,
- request_event_id: &str,
- agreement_event_id: &str,
- payment_event_id: &str,
- listing_addr: &str,
- buyer_pubkey: &str,
- seller_pubkey: &str,
- order_quantity: u32,
- decision: RadrootsOrderSettlementOutcome,
- ) -> String {
- let economics = signed_order_request_economics(trade_order_id, order_quantity);
- let request_event_id = test_event_id(request_event_id);
- let payment_event_id = test_event_id(payment_event_id);
- let agreement_event_id = test_event_id(agreement_event_id);
- let payload = RadrootsOrderSettlementDecision {
- order_id: test_order_id(trade_order_id),
- listing_addr: test_listing_addr(listing_addr),
- seller_pubkey: test_pubkey(seller_pubkey),
- buyer_pubkey: test_pubkey(buyer_pubkey),
- root_event_id: request_event_id.clone(),
- previous_event_id: payment_event_id.clone(),
- agreement_event_id,
- payment_event_id: payment_event_id.clone(),
- quote_id: economics.quote_id.clone(),
- quote_version: economics.quote_version,
- economics_digest: test_economics_digest(
- radroots_order_economics_digest(&economics).expect("k3436 economics digest"),
- ),
- amount: economics.total.amount,
- currency: economics.total.currency,
- decision,
- reason: (decision == RadrootsOrderSettlementOutcome::Rejected)
- .then(|| "reference mismatch".to_owned()),
- };
- let parts =
- order_settlement_decision_event_build(&request_event_id, &payment_event_id, &payload)
- .expect("k3436 draft should build");
- let record_id = format!("app:signed_event:k3436:{event_key}");
- append_trade_signed_event_record(
- paths,
- record_id.as_str(),
- seller_pubkey,
- listing_addr,
- parts,
- )
- }
-
- fn signed_payment_recorded_relay_event(
- buyer: &RadrootsIdentity,
- trade_order_id: &str,
- request_event_id: &str,
- agreement_event_id: &str,
- listing_addr: &str,
- buyer_pubkey: &str,
- seller_pubkey: &str,
- order_quantity: u32,
- ) -> radroots_nostr::prelude::RadrootsNostrEvent {
- let economics = signed_order_request_economics(trade_order_id, order_quantity);
- let request_event_id = test_event_id(request_event_id);
- let agreement_event_id = test_event_id(agreement_event_id);
- let payload = RadrootsOrderPaymentRecord {
- order_id: test_order_id(trade_order_id),
- listing_addr: test_listing_addr(listing_addr),
- buyer_pubkey: test_pubkey(buyer_pubkey),
- seller_pubkey: test_pubkey(seller_pubkey),
- root_event_id: request_event_id.clone(),
- previous_event_id: agreement_event_id.clone(),
- agreement_event_id: agreement_event_id.clone(),
- quote_id: economics.quote_id.clone(),
- quote_version: economics.quote_version,
- economics_digest: test_economics_digest(
- radroots_order_economics_digest(&economics)
- .expect("relay payment economics digest"),
- ),
- amount: economics.total.amount,
- currency: economics.total.currency,
- method: RadrootsOrderPaymentMethod::ManualTransfer,
- reference: Some("relay-memo-1".to_owned()),
- paid_at: Some(1_774_000_050),
- };
- let parts =
- order_payment_record_event_build(&request_event_id, &agreement_event_id, &payload)
- .expect("relay payment draft should build");
-
- radroots_nostr_build_event(parts.kind, parts.content, parts.tags)
- .expect("relay payment builder")
- .sign_with_keys(buyer.keys())
- .expect("relay payment should sign")
- }
-
- fn signed_settlement_decision_relay_event(
- seller: &RadrootsIdentity,
- trade_order_id: &str,
- request_event_id: &str,
- agreement_event_id: &str,
- payment_event_id: &str,
- listing_addr: &str,
- buyer_pubkey: &str,
- seller_pubkey: &str,
- order_quantity: u32,
- decision: RadrootsOrderSettlementOutcome,
- ) -> radroots_nostr::prelude::RadrootsNostrEvent {
- let economics = signed_order_request_economics(trade_order_id, order_quantity);
- let request_event_id = test_event_id(request_event_id);
- let agreement_event_id = test_event_id(agreement_event_id);
- let payment_event_id = test_event_id(payment_event_id);
- let payload = RadrootsOrderSettlementDecision {
- order_id: test_order_id(trade_order_id),
- listing_addr: test_listing_addr(listing_addr),
- seller_pubkey: test_pubkey(seller_pubkey),
- buyer_pubkey: test_pubkey(buyer_pubkey),
- root_event_id: request_event_id.clone(),
- previous_event_id: payment_event_id.clone(),
- agreement_event_id,
- payment_event_id: payment_event_id.clone(),
- quote_id: economics.quote_id.clone(),
- quote_version: economics.quote_version,
- economics_digest: test_economics_digest(
- radroots_order_economics_digest(&economics).expect("relay k3436 economics digest"),
- ),
- amount: economics.total.amount,
- currency: economics.total.currency,
- decision,
- reason: (decision == RadrootsOrderSettlementOutcome::Rejected)
- .then(|| "reference mismatch".to_owned()),
- };
- let parts =
- order_settlement_decision_event_build(&request_event_id, &payment_event_id, &payload)
- .expect("relay k3436 draft should build");
-
- radroots_nostr_build_event(parts.kind, parts.content, parts.tags)
- .expect("relay k3436 builder")
- .sign_with_keys(seller.keys())
- .expect("relay k3436 should sign")
- }
-
- fn selected_account_signing_identity(runtime: &DesktopAppRuntime) -> RadrootsIdentity {
- let account_id = runtime
- .summary()
- .settings_account_projection
- .selected_account
- .as_ref()
- .expect("selected account")
- .account
- .account_id
- .clone();
- let account_id =
- RadrootsIdentityId::parse(account_id.as_str()).expect("selected account id");
- runtime
- .lock_state()
- .accounts_manager
- .as_ref()
- .expect("accounts manager")
- .get_signing_identity(&account_id)
- .expect("signer lookup should succeed")
- .expect("selected account should have local signer")
- }
-
- fn append_signed_order_fulfillment_record(
- paths: &AppDesktopRuntimePaths,
- trade_order_id: &str,
- request_event_id: &str,
- decision_event_id: &str,
- listing_addr: &str,
- buyer_pubkey: &str,
- seller_pubkey: &str,
- ) -> String {
- append_signed_order_fulfillment_record_with_status(
- paths,
- trade_order_id,
- request_event_id,
- decision_event_id,
- listing_addr,
- buyer_pubkey,
- seller_pubkey,
- RadrootsOrderFulfillmentState::ReadyForPickup,
- )
- }
-
- fn append_signed_order_fulfillment_record_with_status(
- paths: &AppDesktopRuntimePaths,
- trade_order_id: &str,
- request_event_id: &str,
- decision_event_id: &str,
- listing_addr: &str,
- buyer_pubkey: &str,
- seller_pubkey: &str,
- status: RadrootsOrderFulfillmentState,
- ) -> String {
- append_signed_order_fulfillment_record_with_status_and_key(
- paths,
- trade_order_id,
- trade_order_id,
- request_event_id,
- decision_event_id,
- listing_addr,
- buyer_pubkey,
- seller_pubkey,
- status,
- )
- }
-
- fn append_signed_order_fulfillment_record_with_status_and_key(
- paths: &AppDesktopRuntimePaths,
- trade_order_id: &str,
- event_key: &str,
- request_event_id: &str,
- prev_event_id: &str,
- listing_addr: &str,
- buyer_pubkey: &str,
- seller_pubkey: &str,
- status: RadrootsOrderFulfillmentState,
- ) -> String {
- let request_event_id = test_event_id(request_event_id);
- let prev_event_id = test_event_id(prev_event_id);
- let payload = RadrootsOrderFulfillmentUpdate {
- order_id: test_order_id(trade_order_id),
- listing_addr: test_listing_addr(listing_addr),
- buyer_pubkey: test_pubkey(buyer_pubkey),
- seller_pubkey: test_pubkey(seller_pubkey),
- status,
- };
- let parts = radroots_sdk::protocol::order::build_fulfillment_update_draft(
- &request_event_id,
- &prev_event_id,
- &payload,
- )
- .expect("fulfillment update draft should build")
- .into_wire_parts();
- let record_id = format!("app:signed_event:fulfillment:{event_key}");
- append_trade_signed_event_record(
- paths,
- record_id.as_str(),
- seller_pubkey,
- listing_addr,
- parts,
- )
- }
-
fn append_signed_order_cancellation_record_with_prev(
paths: &AppDesktopRuntimePaths,
trade_order_id: &str,
@@ -22818,45 +20684,6 @@ mod tests {
)
}
- fn append_signed_order_receipt_record_with_prev(
- paths: &AppDesktopRuntimePaths,
- trade_order_id: &str,
- event_key: &str,
- request_event_id: &str,
- prev_event_id: &str,
- listing_addr: &str,
- buyer_pubkey: &str,
- seller_pubkey: &str,
- received: bool,
- ) -> String {
- let request_event_id = test_event_id(request_event_id);
- let prev_event_id = test_event_id(prev_event_id);
- let payload = RadrootsOrderReceipt {
- order_id: test_order_id(trade_order_id),
- listing_addr: test_listing_addr(listing_addr),
- buyer_pubkey: test_pubkey(buyer_pubkey),
- seller_pubkey: test_pubkey(seller_pubkey),
- received,
- issue: (!received).then(|| "items need review".to_owned()),
- received_at: 1_774_000_030,
- };
- let parts = radroots_sdk::protocol::order::build_buyer_receipt_draft(
- &request_event_id,
- &prev_event_id,
- &payload,
- )
- .expect("buyer receipt draft should build")
- .into_wire_parts();
- let record_id = format!("app:signed_event:receipt:{event_key}");
- append_trade_signed_event_record(
- paths,
- record_id.as_str(),
- buyer_pubkey,
- listing_addr,
- parts,
- )
- }
-
fn append_signed_order_revision_proposal_record_with_prev(
paths: &AppDesktopRuntimePaths,
trade_order_id: &str,
@@ -23452,37 +21279,6 @@ mod tests {
);
}
- fn assert_order_fulfillment_sdk_migration_receipt(
- runtime: &DesktopAppRuntime,
- order_id: OrderId,
- fulfillment: RadrootsOrderFulfillmentState,
- expected_state: AppSdkMigrationState,
- ) {
- assert_order_sdk_migration_receipt(
- runtime,
- format!(
- "app:order_fulfillment:{order_id}:{}",
- order_fulfillment_status_storage_key(fulfillment)
- )
- .as_str(),
- ORDER_FULFILLMENT_UPDATE_OPERATION_KIND,
- expected_state,
- );
- }
-
- fn assert_order_receipt_sdk_migration_receipt(
- runtime: &DesktopAppRuntime,
- order_id: OrderId,
- expected_state: AppSdkMigrationState,
- ) {
- assert_order_sdk_migration_receipt(
- runtime,
- format!("app:order_receipt:{order_id}").as_str(),
- ORDER_RECEIPT_RECORD_OPERATION_KIND,
- expected_state,
- );
- }
-
fn assert_order_sdk_migration_receipt(
runtime: &DesktopAppRuntime,
source_record_id: &str,
diff --git a/crates/desktop/src/source_guards.rs b/crates/desktop/src/source_guards.rs
@@ -87,10 +87,7 @@ const ALLOWED_WINDOW_LITERALS: &[&str] = &[
"buyer-order-keep-current",
"buyer-order-keep-order",
"buyer-order-close-issue",
- "buyer-order-mark-received",
- "buyer-order-report-issue",
"buyer-order-repeat-demand",
- "buyer-order-send-issue",
"buyer-orders-retry-coordination",
"personal_orders",
"buyer.add_to_cart_failed",
@@ -101,8 +98,6 @@ const ALLOWED_WINDOW_LITERALS: &[&str] = &[
"buyer.order_open_failed",
"buyer.order_cancel_failed",
"buyer.order_coordination_retry_failed",
- "buyer.order_issue_receipt_failed",
- "buyer.order_receipt_failed",
"buyer.order_revision_accept_failed",
"buyer.order_revision_decline_failed",
"buyer.repeat_demand_failed",
@@ -138,9 +133,6 @@ const ALLOWED_WINDOW_LITERALS: &[&str] = &[
"failed to accept buyer order change",
"failed to cancel buyer order",
"failed to keep buyer order",
- "failed to mark buyer order received",
- "failed to report buyer order issue",
- "failed to publish order fulfillment update",
"failed to open existing product editor",
"failed to open new product editor",
"failed to acknowledge reminder",
@@ -214,15 +206,12 @@ const ALLOWED_WINDOW_LITERALS: &[&str] = &[
"today-reminder-chip",
"https://auth.example/challenge",
"identity",
- "items need review",
"localhost",
"npub1",
"npub1qqqqq...qqqqqq",
"npub1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
"npub1sxczr...5lkheq",
"npub1sxczrq2dp4jtehcm8mtemj975u5ytf2d7mc6dpuuq3rzkjzr76ls5lkheq",
- "receipt-clean",
- "receipt-issue",
"guest",
"finder unavailable",
"orders",
@@ -247,27 +236,19 @@ const ALLOWED_WINDOW_LITERALS: &[&str] = &[
"pack-day-reveal-bundle",
"pack_day.export_failed",
"pack_day.route_failed",
- "orders-detail-publish-delivered",
- "orders-detail-publish-out-for-delivery",
- "orders-detail-publish-preparing",
- "orders-detail-publish-ready-for-pickup",
- "orders-detail-publish-seller-cancelled",
"orders-filter-all",
"orders-filter-completed",
"orders-filter-needs-action",
"orders-filter-packed",
- "orders-filter-refunded",
"orders-filter-scheduled",
"orders-recovery-open",
"orders-recovery-review",
"orders-recovery-reopen",
"orders-recovery-resolve",
- "orders-row-action-publish-fulfillment",
"orders-row-action-review",
"orders-row-open",
"orders.detail_open_failed",
"orders.filter_update_failed",
- "orders.fulfillment_publish_failed",
"orders.recovery_reopen_failed",
"orders.recovery_resolve_failed",
"orders.recovery_review_failed",
@@ -668,17 +649,10 @@ const REQUIRED_WINDOW_COPY_KEYS: &[&str] = &[
"AppTextKey::PersonalOrdersDetailFulfillmentLabel",
"AppTextKey::PersonalOrdersDetailTotalLabel",
"AppTextKey::PersonalOrdersDetailNoteLabel",
- "AppTextKey::PersonalOrdersDetailReceiptLabel",
"AppTextKey::PersonalOrdersDetailItemsTitle",
"AppTextKey::PersonalOrdersActionCancel",
"AppTextKey::PersonalOrdersActionAcceptChange",
"AppTextKey::PersonalOrdersActionKeepOrder",
- "AppTextKey::PersonalOrdersActionMarkReceived",
- "AppTextKey::PersonalOrdersActionReportIssue",
- "AppTextKey::PersonalOrdersActionSendReceiptIssue",
- "AppTextKey::PersonalOrdersActionCloseReceiptIssue",
- "AppTextKey::PersonalOrdersReceiptIssueLabel",
- "AppTextKey::PersonalOrdersReceiptIssuePlaceholder",
"AppTextKey::PersonalOrdersRepeatDemandTitle",
"AppTextKey::PersonalOrdersRepeatDemandActionEligible",
"AppTextKey::PersonalOrdersRepeatDemandActionPartial",
@@ -722,7 +696,6 @@ const REQUIRED_WINDOW_COPY_KEYS: &[&str] = &[
"AppTextKey::OrdersStatusScheduled",
"AppTextKey::OrdersStatusInHandoff",
"AppTextKey::OrdersStatusCompleted",
- "AppTextKey::OrdersStatusRefunded",
"AppTextKey::OrdersTableTitle",
"AppTextKey::OrdersColumnOrder",
"AppTextKey::OrdersColumnStatus",
@@ -730,12 +703,6 @@ const REQUIRED_WINDOW_COPY_KEYS: &[&str] = &[
"AppTextKey::OrdersColumnPickup",
"AppTextKey::OrdersColumnAction",
"AppTextKey::OrdersActionReview",
- "AppTextKey::OrdersActionPreparing",
- "AppTextKey::OrdersActionReadyForPickup",
- "AppTextKey::OrdersActionOutForDelivery",
- "AppTextKey::OrdersActionMarkDelivered",
- "AppTextKey::OrdersActionCancelFulfillment",
- "AppTextKey::OrdersActionUpdateFulfillment",
"AppTextKey::OrdersEmptyTitle",
"AppTextKey::OrdersEmptyBody",
"AppTextKey::OrdersEmptyNeedsActionTitle",
@@ -756,38 +723,21 @@ const REQUIRED_WINDOW_COPY_KEYS: &[&str] = &[
"AppTextKey::TradeValidationReceiptTypeStateCheckpoint",
"AppTextKey::TradeWorkflowAxisAgreement",
"AppTextKey::TradeWorkflowAxisRevision",
- "AppTextKey::TradeWorkflowAxisFulfillment",
"AppTextKey::TradeWorkflowAxisInventory",
- "AppTextKey::TradeWorkflowAxisPayment",
- "AppTextKey::TradeWorkflowAxisReceipt",
"AppTextKey::TradeWorkflowAxisSource",
"AppTextKey::TradeWorkflowAgreementOrdered",
"AppTextKey::TradeWorkflowAgreementConfirmed",
"AppTextKey::TradeWorkflowAgreementDeclined",
"AppTextKey::TradeWorkflowAgreementCancelled",
- "AppTextKey::TradeWorkflowAgreementCompleted",
"AppTextKey::TradeWorkflowAgreementNeedsReview",
"AppTextKey::TradeWorkflowRevisionNone",
"AppTextKey::TradeWorkflowRevisionChangeProposed",
"AppTextKey::TradeWorkflowRevisionUpdated",
"AppTextKey::TradeWorkflowRevisionKeptAsPlaced",
- "AppTextKey::TradeWorkflowFulfillmentConfirmed",
- "AppTextKey::TradeWorkflowFulfillmentPreparing",
- "AppTextKey::TradeWorkflowFulfillmentReadyForPickup",
- "AppTextKey::TradeWorkflowFulfillmentOutForDelivery",
- "AppTextKey::TradeWorkflowFulfillmentDelivered",
- "AppTextKey::TradeWorkflowFulfillmentCancelled",
"AppTextKey::TradeWorkflowInventoryAvailable",
"AppTextKey::TradeWorkflowInventoryReserved",
"AppTextKey::TradeWorkflowInventorySoldOut",
"AppTextKey::TradeWorkflowInventoryNeedsReview",
- "AppTextKey::TradeWorkflowPaymentNotRecorded",
- "AppTextKey::TradeWorkflowPaymentPending",
- "AppTextKey::TradeWorkflowPaymentRecorded",
- "AppTextKey::TradeWorkflowPaymentSettled",
- "AppTextKey::TradeWorkflowPaymentNeedsReview",
- "AppTextKey::TradeWorkflowReceiptReceived",
- "AppTextKey::TradeWorkflowReceiptNeedsReview",
"AppTextKey::TradeWorkflowProvenanceApp",
"AppTextKey::TradeWorkflowProvenanceCli",
"AppTextKey::TradeWorkflowProvenanceRelay",
@@ -796,8 +746,6 @@ const REQUIRED_WINDOW_COPY_KEYS: &[&str] = &[
"AppTextKey::OrdersRecoverySectionTitle",
"AppTextKey::OrdersRecoveryMissedPickupTitle",
"AppTextKey::OrdersRecoveryMissedPickupBody",
- "AppTextKey::OrdersRecoveryRefundFollowUpTitle",
- "AppTextKey::OrdersRecoveryRefundFollowUpBody",
"AppTextKey::OrdersRecoveryLastUpdatedLabel",
"AppTextKey::OrdersRecoveryActionOpenFollowUp",
"AppTextKey::OrdersRecoveryActionStartReview",
diff --git a/crates/desktop/src/window.rs b/crates/desktop/src/window.rs
@@ -29,8 +29,8 @@ use radroots_app_state::{
PackDayPrintRequest, derive_product_publish_blockers,
};
use radroots_app_sync::{
- AppOrderReceiptOutcome, AppSyncRunStatus, SyncAggregateRef, SyncCheckpointState, SyncConflict,
- SyncConflictKind, SyncConflictResolutionStatus, SyncConflictSeverity,
+ AppSyncRunStatus, SyncAggregateRef, SyncCheckpointState, SyncConflict, SyncConflictKind,
+ SyncConflictResolutionStatus, SyncConflictSeverity,
};
use radroots_app_ui::{
APP_UI_THEME, AppCheckboxFieldSpec, AppFormFieldSpec, AppPillTabSpec,
@@ -68,8 +68,8 @@ use radroots_app_view::{
FarmProfileRecord, FarmReadinessBlocker, FarmRulesProjection, FarmRulesReadiness,
FarmSetupBlocker, FarmSetupDraft, FarmSummary, FarmTimingConflictKind, FarmerSection,
FulfillmentWindowId, FulfillmentWindowRecord, FulfillmentWindowSummary, LoggedOutStartupPhase,
- OrderDetailItemRow, OrderDetailProjection, OrderFulfillmentAction, OrderId, OrderListRow,
- OrderPrimaryAction, OrderRecoveryProjection, OrderStatus, OrdersFilter, OrdersListRow,
+ OrderDetailItemRow, OrderDetailProjection, OrderId, OrderListRow, OrderPrimaryAction,
+ OrderRecoveryProjection, OrderStatus, OrdersFilter, OrdersListRow,
PackDayBatchPrintFailureKind, PackDayBatchPrintStatus, PackDayExportBundle,
PackDayExportStatus, PackDayHostHandoffKind, PackDayHostHandoffStatus, PackDayPackListRow,
PackDayPrintFailureKind, PackDayPrintKind, PackDayPrintStatus, PackDayProductTotalRow,
@@ -80,8 +80,7 @@ use radroots_app_view::{
ReminderLogEntryProjection, ReminderLogProjection, ReminderSurface, ReminderUrgency,
RepeatDemandEligibility, RepeatDemandHandoffProjection, SettingsAccountProjection,
ShellSection, TodayAgendaProjection, TodaySetupTaskKind, TradeAgreementStatus,
- TradeEconomicsProjection, TradeFulfillmentStatus, TradeInventoryStatus,
- TradePaymentDisplayStatus, TradeReceiptProjection, TradeRevisionStatus,
+ TradeEconomicsProjection, TradeInventoryStatus, TradeRevisionStatus,
TradeValidationReceiptProjection, TradeValidationReceiptResult, TradeValidationReceiptType,
TradeWorkflowProjection, TradeWorkflowSource,
};
@@ -176,7 +175,6 @@ enum HomeFocusedView {
BuyerProductDetail(PersonalSection),
BuyerOrderReview,
BuyerOrderDetail(OrderId),
- BuyerReceiptIssue(OrderId),
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
@@ -801,13 +799,6 @@ fn farmer_order_detail_focus_after_open(
}
}
-fn buyer_receipt_issue_focus_after_submit(
- runtime_changed: bool,
- order_id: OrderId,
-) -> Option<HomeFocusedView> {
- runtime_changed.then_some(HomeFocusedView::BuyerOrderDetail(order_id))
-}
-
pub fn home_window_options(cx: &mut App) -> WindowOptions {
let (launch_width_px, launch_height_px) = home_window_launch_size_px();
let (minimum_width_px, minimum_height_px) = home_window_minimum_size_px();
@@ -885,7 +876,6 @@ pub struct HomeView {
farm_setup_form: Option<FarmSetupFormState>,
personal_search: Option<PersonalSearchState>,
buyer_order_review_form: Option<BuyerOrderReviewFormState>,
- buyer_receipt_issue_form: Option<BuyerReceiptIssueFormState>,
products_search: Option<ProductsSearchState>,
products_stock_editor: Option<ProductsStockEditorState>,
product_editor_form: Option<ProductEditorFormState>,
@@ -937,7 +927,6 @@ struct HomeAutoFocusState {
has_farm_setup_form: bool,
has_personal_search_input: bool,
has_buyer_order_review_form: bool,
- has_buyer_receipt_issue_form: bool,
has_products_search_input: bool,
has_products_stock_editor: bool,
has_product_editor_form: bool,
@@ -954,7 +943,6 @@ enum HomeAutoFocusTarget {
BuyerDetailBack,
BuyerCartOpenOrderReview,
BuyerOrderReviewNameInput,
- BuyerReceiptIssueInput,
BuyerOrderOpenFirst,
BuyerOrderConfirmReplace,
BuyerOrderRepeatDemand,
@@ -973,7 +961,6 @@ enum HomeAutoFocusTarget {
ProductsStockInput,
ProductEditorTitleInput,
OrdersRowOpenFirst,
- OrdersDetailPublishFulfillmentFirst,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
@@ -1011,7 +998,6 @@ impl HomeView {
farm_setup_form: None,
personal_search: None,
buyer_order_review_form: None,
- buyer_receipt_issue_form: None,
products_search: None,
products_stock_editor: None,
product_editor_form: None,
@@ -1037,7 +1023,6 @@ impl HomeView {
has_farm_setup_form: self.farm_setup_form.is_some(),
has_personal_search_input: self.personal_search.is_some(),
has_buyer_order_review_form: self.buyer_order_review_form.is_some(),
- has_buyer_receipt_issue_form: self.buyer_receipt_issue_form.is_some(),
has_products_search_input: self.products_search.is_some(),
has_products_stock_editor: self.products_stock_editor.is_some(),
has_product_editor_form: self.product_editor_form.is_some(),
@@ -1110,12 +1095,6 @@ impl HomeView {
.update(cx, |input, cx| input.focus(window, cx));
}
}
- HomeAutoFocusTarget::BuyerReceiptIssueInput => {
- if let Some(form) = self.buyer_receipt_issue_form.as_ref() {
- form.issue_input
- .update(cx, |input, cx| input.focus(window, cx));
- }
- }
HomeAutoFocusTarget::BuyerOrderOpenFirst => {
focus_button(window, ("buyer-order-open", 0_usize), cx);
}
@@ -1180,9 +1159,6 @@ impl HomeView {
HomeAutoFocusTarget::OrdersRowOpenFirst => {
focus_button(window, ("orders-row-open", 0_usize), cx);
}
- HomeAutoFocusTarget::OrdersDetailPublishFulfillmentFirst => {
- focus_button(window, "orders-detail-publish-preparing", cx);
- }
}
}
@@ -1778,28 +1754,6 @@ impl HomeView {
}
}
- fn sync_buyer_receipt_issue_form(&mut self, runtime_summary: &DesktopAppRuntimeSummary) {
- let Some(form) = self.buyer_receipt_issue_form.as_ref() else {
- return;
- };
-
- if home_stage(runtime_summary) != HomeStage::BuyerWorkspace
- || selected_personal_section(runtime_summary) != PersonalSection::Orders
- {
- self.buyer_receipt_issue_form = None;
- return;
- }
-
- let Some(detail) = runtime_summary.personal_projection.orders.detail.as_ref() else {
- self.buyer_receipt_issue_form = None;
- return;
- };
-
- if detail.order_id != form.order_id || !buyer_receipt_actions_available(detail) {
- self.buyer_receipt_issue_form = None;
- }
- }
-
fn sync_products_stock_editor(&mut self, runtime_summary: &DesktopAppRuntimeSummary) {
let Some(editor) = self.products_stock_editor.as_ref() else {
return;
@@ -2138,25 +2092,6 @@ impl HomeView {
}
}
- fn handle_buyer_receipt_issue_input_event(
- &mut self,
- state: &Entity<InputState>,
- event: &InputEvent,
- _: &mut Window,
- cx: &mut Context<Self>,
- ) {
- if !matches!(event, InputEvent::Change) {
- return;
- }
-
- let Some(form) = self.buyer_receipt_issue_form.as_ref() else {
- return;
- };
- if form.issue_input == *state {
- cx.notify();
- }
- }
-
fn toggle_personal_search_fulfillment_method(
&mut self,
method: FarmOrderMethod,
@@ -2418,13 +2353,6 @@ impl HomeView {
) else {
return;
};
- if self
- .buyer_receipt_issue_form
- .as_ref()
- .is_some_and(|form| form.order_id != order_id)
- {
- self.buyer_receipt_issue_form = None;
- }
self.focused_view = Some(focused_view);
cx.notify();
}
@@ -2937,31 +2865,6 @@ impl HomeView {
}
}
- fn publish_order_fulfillment_update(
- &mut self,
- order_id: OrderId,
- action: OrderFulfillmentAction,
- cx: &mut Context<Self>,
- ) {
- match self
- .runtime
- .publish_order_fulfillment_update(order_id, action)
- {
- Ok(true) => cx.notify(),
- Ok(false) => {}
- Err(runtime_error) => {
- error!(
- target: "orders",
- event = "orders.fulfillment_publish_failed",
- error = %runtime_error,
- order_id = %order_id,
- fulfillment_state = action.storage_key(),
- "failed to publish order fulfillment update"
- );
- }
- }
- }
-
fn cancel_buyer_order(&mut self, order_id: OrderId, cx: &mut Context<Self>) {
match self.runtime.publish_buyer_order_cancel(order_id) {
Ok(true) => cx.notify(),
@@ -3010,98 +2913,6 @@ impl HomeView {
}
}
- fn open_buyer_receipt_issue_form(
- &mut self,
- order_id: OrderId,
- window: &mut Window,
- cx: &mut Context<Self>,
- ) {
- self.buyer_receipt_issue_form = Some(BuyerReceiptIssueFormState::new(order_id, window, cx));
- self.focused_view = Some(HomeFocusedView::BuyerReceiptIssue(order_id));
- cx.notify();
- }
-
- fn close_buyer_receipt_issue_form(&mut self, cx: &mut Context<Self>) {
- let order_id = self
- .buyer_receipt_issue_form
- .as_ref()
- .map(|form| form.order_id);
- let cleared = self.buyer_receipt_issue_form.take().is_some();
- let focus_changed = order_id
- .map(|order_id| {
- self.clear_focused_view_matching(HomeFocusedView::BuyerReceiptIssue(order_id))
- })
- .unwrap_or(false);
- if focus_changed {
- if let Some(order_id) = order_id {
- self.focused_view = Some(HomeFocusedView::BuyerOrderDetail(order_id));
- }
- }
- if cleared || focus_changed {
- cx.notify();
- }
- }
-
- fn mark_buyer_order_received(&mut self, order_id: OrderId, cx: &mut Context<Self>) {
- match self
- .runtime
- .publish_buyer_order_receipt(order_id, AppOrderReceiptOutcome::Received)
- {
- Ok(true) => {
- if self
- .buyer_receipt_issue_form
- .as_ref()
- .is_some_and(|form| form.order_id == order_id)
- {
- self.buyer_receipt_issue_form = None;
- }
- cx.notify();
- }
- Ok(false) => {}
- Err(runtime_error) => {
- error!(
- target: "personal_orders",
- event = "buyer.order_receipt_failed",
- error = %runtime_error,
- order_id = %order_id,
- "failed to mark buyer order received"
- );
- }
- }
- }
-
- fn submit_buyer_order_issue_receipt(&mut self, order_id: OrderId, cx: &mut Context<Self>) {
- let Some(issue) = self
- .buyer_receipt_issue_form
- .as_ref()
- .filter(|form| form.order_id == order_id)
- .and_then(|form| AppOrderReceiptOutcome::issue(form.issue_text(cx)))
- else {
- return;
- };
-
- match self.runtime.publish_buyer_order_receipt(order_id, issue) {
- Ok(runtime_changed) => {
- if let Some(focused_view) =
- buyer_receipt_issue_focus_after_submit(runtime_changed, order_id)
- {
- self.buyer_receipt_issue_form = None;
- self.focused_view = Some(focused_view);
- cx.notify();
- }
- }
- Err(runtime_error) => {
- error!(
- target: "personal_orders",
- event = "buyer.order_issue_receipt_failed",
- error = %runtime_error,
- order_id = %order_id,
- "failed to report buyer order issue"
- );
- }
- }
- }
-
fn start_order_recovery(
&mut self,
order_id: OrderId,
@@ -3911,7 +3722,6 @@ impl HomeView {
Some(
buyer_order_detail_card(
detail,
- None,
runtime
.personal_projection
.cart
@@ -3926,19 +3736,6 @@ impl HomeView {
.into_any_element(),
)
}
- HomeFocusedView::BuyerReceiptIssue(order_id) => {
- let detail = runtime
- .personal_projection
- .orders
- .detail
- .as_ref()
- .filter(|detail| detail.order_id == order_id)?;
- let issue_form = self
- .buyer_receipt_issue_form
- .as_ref()
- .filter(|form| form.order_id == order_id)?;
- Some(buyer_receipt_issue_focused_view(detail, issue_form, cx))
- }
HomeFocusedView::FarmSetup
| HomeFocusedView::ProductEditor
| HomeFocusedView::FarmerOrderDetail(_) => None,
@@ -4311,8 +4108,7 @@ impl HomeView {
}
HomeFocusedView::BuyerProductDetail(_)
| HomeFocusedView::BuyerOrderReview
- | HomeFocusedView::BuyerOrderDetail(_)
- | HomeFocusedView::BuyerReceiptIssue(_) => None,
+ | HomeFocusedView::BuyerOrderDetail(_) => None,
}
}
@@ -4476,15 +4272,6 @@ impl HomeView {
this.select_orders_filter(OrdersFilter::Completed, cx)
}),
cx,
- ))
- .child(choice_button(
- "orders-filter-refunded",
- app_shared_text(AppTextKey::OrdersStatusRefunded),
- projection.query.filter == OrdersFilter::Refunded,
- cx.listener(|this, _, _, cx| {
- this.select_orders_filter(OrdersFilter::Refunded, cx)
- }),
- cx,
)),
))
.when(!projection.reminders.is_empty(), |this| {
@@ -5094,33 +4881,6 @@ impl HomeView {
on_close: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static,
cx: &mut Context<Self>,
) -> AnyElement {
- let fulfillment_actions = (!detail.fulfillment_actions.is_empty()).then(|| {
- app_form_section(
- app_shared_text(AppTextKey::TradeWorkflowAxisFulfillment),
- app_cluster(APP_UI_THEME.foundation.spacing.tight_px).children(
- detail
- .fulfillment_actions
- .iter()
- .copied()
- .map(|action| {
- action_button_compact(
- order_detail_fulfillment_action_id(action),
- app_shared_text(order_fulfillment_action_label_key(action)),
- cx.listener({
- let order_id = detail.order_id;
- move |this, _, _, cx| {
- this.publish_order_fulfillment_update(order_id, action, cx)
- }
- }),
- cx,
- )
- .into_any_element()
- })
- .collect::<Vec<_>>(),
- ),
- )
- });
-
app_focused_detail_view(
app_shared_text(AppTextKey::OrdersDetailTitle),
app_stack_v(APP_UI_THEME.shells.home_stack_gap_px)
@@ -5169,10 +4929,7 @@ impl HomeView {
this.child(home_body_text(app_shared_text(AppTextKey::ValueNone)))
}),
))
- .child(self.render_order_recovery_section(detail, cx))
- .when_some(fulfillment_actions, |this, fulfillment_actions| {
- this.child(fulfillment_actions)
- }),
+ .child(self.render_order_recovery_section(detail, cx)),
text_button(
"orders-detail-back",
app_shared_text(AppTextKey::PersonalDetailBackAction),
@@ -5204,17 +4961,6 @@ impl HomeView {
.find(|record| record.kind == RecoveryKind::MissedPickup),
cx,
),
- )
- .child(
- self.render_order_recovery_card(
- detail.order_id,
- RecoveryKind::RefundFollowUp,
- detail
- .recoveries
- .iter()
- .find(|record| record.kind == RecoveryKind::RefundFollowUp),
- cx,
- ),
),
)
.into_any_element()
@@ -5484,17 +5230,6 @@ impl HomeView {
let order_id = row.order_id;
move |this, _, _, cx| this.open_order_detail(order_id, cx)
}),
- cx.listener({
- let order_id = row.order_id;
- let action = row
- .primary_action
- .and_then(OrderPrimaryAction::fulfillment_action);
- move |this, _, _, cx| {
- if let Some(action) = action {
- this.publish_order_fulfillment_update(order_id, action, cx);
- }
- }
- }),
cx,
);
@@ -5512,7 +5247,6 @@ impl Render for HomeView {
self.sync_farm_setup_form(&runtime_summary, window, cx);
self.sync_personal_search(&runtime_summary, window, cx);
self.sync_buyer_order_review_form(&runtime_summary, window, cx);
- self.sync_buyer_receipt_issue_form(&runtime_summary);
self.sync_products_search(&runtime_summary, window, cx);
self.sync_products_stock_editor(&runtime_summary);
self.sync_product_editor_form(&runtime_summary, window, cx);
@@ -5982,43 +5716,6 @@ fn sync_order_review_input(
});
}
-struct BuyerReceiptIssueFormState {
- order_id: OrderId,
- issue_input: Entity<InputState>,
- _issue_subscription: Subscription,
-}
-
-impl BuyerReceiptIssueFormState {
- fn new(order_id: OrderId, window: &mut Window, cx: &mut Context<HomeView>) -> Self {
- let issue_input = cx.new(|cx| {
- InputState::new(window, cx)
- .placeholder(app_shared_text(
- AppTextKey::PersonalOrdersReceiptIssuePlaceholder,
- ))
- .default_value(String::new())
- });
- let issue_subscription = cx.subscribe_in(
- &issue_input,
- window,
- HomeView::handle_buyer_receipt_issue_input_event,
- );
-
- Self {
- order_id,
- issue_input,
- _issue_subscription: issue_subscription,
- }
- }
-
- fn issue_text(&self, cx: &App) -> String {
- self.issue_input.read(cx).value().trim().to_owned()
- }
-
- fn can_submit(&self, cx: &App) -> bool {
- !self.issue_text(cx).is_empty()
- }
-}
-
struct ProductsSearchState {
account_id: String,
input: Entity<InputState>,
@@ -9363,9 +9060,7 @@ fn buyer_auto_focus_target(
.is_some_and(|confirmation| {
confirmation.incoming_farm_display_name == detail.farm_display_name
});
- if state.has_buyer_receipt_issue_form {
- Some(HomeAutoFocusTarget::BuyerReceiptIssueInput)
- } else if replace_confirmation {
+ if replace_confirmation {
Some(HomeAutoFocusTarget::BuyerOrderConfirmReplace)
} else if detail.repeat_demand.as_ref().is_some_and(|repeat_demand| {
repeat_demand.eligibility != RepeatDemandEligibility::Unavailable
@@ -9412,15 +9107,7 @@ fn farmer_auto_focus_target(
}
}
FarmerSection::Orders if farmer_products_available(runtime) => {
- if let Some(detail) = runtime.orders_projection.detail.as_ref() {
- if !detail.fulfillment_actions.is_empty() {
- Some(HomeAutoFocusTarget::OrdersDetailPublishFulfillmentFirst)
- } else if !runtime.orders_projection.list.rows.is_empty() {
- Some(HomeAutoFocusTarget::OrdersRowOpenFirst)
- } else {
- None
- }
- } else if !runtime.orders_projection.list.rows.is_empty() {
+ if !runtime.orders_projection.list.rows.is_empty() {
Some(HomeAutoFocusTarget::OrdersRowOpenFirst)
} else {
None
@@ -12183,27 +11870,10 @@ fn trade_workflow_detail_badge_strip(workflow: &TradeWorkflowProjection) -> AnyE
),
];
- if let Some(fulfillment) = workflow.fulfillment {
- badges.push(trade_workflow_labeled_key_badge(
- AppTextKey::TradeWorkflowAxisFulfillment,
- trade_fulfillment_status_key(fulfillment),
- ));
- }
- if let Some(receipt) = workflow.receipt.as_ref() {
- badges.push(trade_workflow_labeled_key_badge(
- AppTextKey::TradeWorkflowAxisReceipt,
- buyer_receipt_status_key(receipt),
- ));
- }
-
badges.push(trade_workflow_labeled_key_badge(
AppTextKey::TradeWorkflowAxisInventory,
trade_inventory_status_key(workflow.inventory),
));
- badges.push(trade_workflow_labeled_key_badge(
- AppTextKey::TradeWorkflowAxisPayment,
- trade_payment_display_status_key(workflow.payment),
- ));
if workflow.provenance.primary_source != TradeWorkflowSource::Unknown {
badges.push(trade_workflow_labeled_key_badge(
AppTextKey::TradeWorkflowAxisSource,
@@ -12228,21 +11898,9 @@ fn trade_workflow_list_badge_strip(workflow: &TradeWorkflowProjection) -> AnyEle
)));
}
- if let Some(fulfillment) = workflow.fulfillment {
- badges.push(trade_workflow_value_badge(trade_fulfillment_status_key(
- fulfillment,
- )));
- }
- if let Some(receipt) = workflow.receipt.as_ref() {
- badges.push(trade_workflow_value_badge(buyer_receipt_status_key(
- receipt,
- )));
- }
-
- badges.push(trade_workflow_labeled_key_badge(
- AppTextKey::TradeWorkflowAxisPayment,
- trade_payment_display_status_key(workflow.payment),
- ));
+ badges.push(trade_workflow_value_badge(trade_inventory_status_key(
+ workflow.inventory,
+ )));
app_cluster(APP_UI_THEME.foundation.spacing.tight_px)
.w_full()
@@ -12256,16 +11914,9 @@ fn trade_workflow_status_stack(workflow: &TradeWorkflowProjection) -> AnyElement
.child(trade_workflow_value_badge(trade_agreement_status_key(
workflow.agreement,
)))
- .when_some(workflow.fulfillment, |this, fulfillment| {
- this.child(trade_workflow_value_badge(trade_fulfillment_status_key(
- fulfillment,
- )))
- })
- .when_some(workflow.receipt.as_ref(), |this, receipt| {
- this.child(trade_workflow_value_badge(buyer_receipt_status_key(
- receipt,
- )))
- })
+ .child(trade_workflow_value_badge(trade_inventory_status_key(
+ workflow.inventory,
+ )))
.into_any_element()
}
@@ -12284,7 +11935,6 @@ fn trade_agreement_status_key(status: TradeAgreementStatus) -> AppTextKey {
TradeAgreementStatus::Confirmed => AppTextKey::TradeWorkflowAgreementConfirmed,
TradeAgreementStatus::Declined => AppTextKey::TradeWorkflowAgreementDeclined,
TradeAgreementStatus::Cancelled => AppTextKey::TradeWorkflowAgreementCancelled,
- TradeAgreementStatus::Completed => AppTextKey::TradeWorkflowAgreementCompleted,
TradeAgreementStatus::NeedsReview => AppTextKey::TradeWorkflowAgreementNeedsReview,
}
}
@@ -12298,21 +11948,6 @@ fn trade_revision_status_key(status: TradeRevisionStatus) -> AppTextKey {
}
}
-fn trade_fulfillment_status_key(status: TradeFulfillmentStatus) -> AppTextKey {
- match status {
- TradeFulfillmentStatus::Confirmed => AppTextKey::TradeWorkflowFulfillmentConfirmed,
- TradeFulfillmentStatus::Preparing => AppTextKey::TradeWorkflowFulfillmentPreparing,
- TradeFulfillmentStatus::ReadyForPickup => {
- AppTextKey::TradeWorkflowFulfillmentReadyForPickup
- }
- TradeFulfillmentStatus::OutForDelivery => {
- AppTextKey::TradeWorkflowFulfillmentOutForDelivery
- }
- TradeFulfillmentStatus::Delivered => AppTextKey::TradeWorkflowFulfillmentDelivered,
- TradeFulfillmentStatus::Cancelled => AppTextKey::TradeWorkflowFulfillmentCancelled,
- }
-}
-
fn trade_inventory_status_key(status: TradeInventoryStatus) -> AppTextKey {
match status {
TradeInventoryStatus::Available => AppTextKey::TradeWorkflowInventoryAvailable,
@@ -12322,16 +11957,6 @@ fn trade_inventory_status_key(status: TradeInventoryStatus) -> AppTextKey {
}
}
-fn trade_payment_display_status_key(status: TradePaymentDisplayStatus) -> AppTextKey {
- match status {
- TradePaymentDisplayStatus::NotRecorded => AppTextKey::TradeWorkflowPaymentNotRecorded,
- TradePaymentDisplayStatus::Pending => AppTextKey::TradeWorkflowPaymentPending,
- TradePaymentDisplayStatus::Recorded => AppTextKey::TradeWorkflowPaymentRecorded,
- TradePaymentDisplayStatus::Settled => AppTextKey::TradeWorkflowPaymentSettled,
- TradePaymentDisplayStatus::NeedsReview => AppTextKey::TradeWorkflowPaymentNeedsReview,
- }
-}
-
fn trade_workflow_source_key(source: TradeWorkflowSource) -> AppTextKey {
match source {
TradeWorkflowSource::App => AppTextKey::TradeWorkflowProvenanceApp,
@@ -12457,7 +12082,6 @@ fn buyer_orders_list_entry(
fn buyer_order_detail_card(
detail: &BuyerOrderDetailProjection,
- issue_form: Option<&BuyerReceiptIssueFormState>,
replace_confirmation: Option<&BuyerCartReplaceConfirmationProjection>,
on_close: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static,
cx: &mut Context<HomeView>,
@@ -12490,9 +12114,6 @@ fn buyer_order_detail_card(
order_optional_text(detail.order_note.as_deref()),
),
]))
- .when_some(detail.workflow.receipt.as_ref(), |this, receipt| {
- this.child(buyer_receipt_summary_section(receipt))
- })
.when(!detail.validation_receipts.is_empty(), |this| {
this.child(validation_receipts_summary_section(
&detail.validation_receipts,
@@ -12548,57 +12169,16 @@ fn buyer_order_detail_card(
)
},
)
- .when(
- matches!(
- detail.status,
- BuyerOrderStatus::Placed | BuyerOrderStatus::Scheduled
- ),
- |this| {
- this.child(action_button_compact(
- "buyer-order-cancel",
- app_shared_text(AppTextKey::PersonalOrdersActionCancel),
- cx.listener({
- let order_id = detail.order_id;
- move |this, _, _, cx| this.cancel_buyer_order(order_id, cx)
- }),
- cx,
- ))
- },
- )
- .when(buyer_receipt_actions_available(detail), |this| {
- this.child(
- app_stack_v(APP_UI_THEME.foundation.spacing.small_px)
- .w_full()
- .child(
- app_cluster(APP_UI_THEME.foundation.spacing.small_px)
- .w_full()
- .child(action_button_primary(
- "buyer-order-mark-received",
- app_shared_text(AppTextKey::PersonalOrdersActionMarkReceived),
- cx.listener({
- let order_id = detail.order_id;
- move |this, _, _, cx| {
- this.mark_buyer_order_received(order_id, cx)
- }
- }),
- cx,
- ))
- .child(action_button_compact(
- "buyer-order-report-issue",
- app_shared_text(AppTextKey::PersonalOrdersActionReportIssue),
- cx.listener({
- let order_id = detail.order_id;
- move |this, _, window, cx| {
- this.open_buyer_receipt_issue_form(order_id, window, cx)
- }
- }),
- cx,
- )),
- )
- .when_some(issue_form, |this, form| {
- this.child(buyer_receipt_issue_form_section(form, cx))
- }),
- )
+ .when(detail.status == BuyerOrderStatus::Placed, |this| {
+ this.child(action_button_compact(
+ "buyer-order-cancel",
+ app_shared_text(AppTextKey::PersonalOrdersActionCancel),
+ cx.listener({
+ let order_id = detail.order_id;
+ move |this, _, _, cx| this.cancel_buyer_order(order_id, cx)
+ }),
+ cx,
+ ))
})
.when_some(detail.repeat_demand.as_ref(), |this, repeat_demand| {
this.child(app_form_section(
@@ -12684,21 +12264,6 @@ fn buyer_order_detail_card(
)
}
-fn buyer_receipt_summary_section(receipt: &TradeReceiptProjection) -> AnyElement {
- app_form_section(
- app_shared_text(AppTextKey::PersonalOrdersDetailReceiptLabel),
- app_stack_v(APP_UI_THEME.foundation.spacing.small_px)
- .w_full()
- .child(trade_workflow_value_badge(buyer_receipt_status_key(
- receipt,
- )))
- .when_some(receipt.issue.as_ref(), |this, issue| {
- this.child(home_body_text(issue.clone()))
- }),
- )
- .into_any_element()
-}
-
fn validation_receipts_summary_section(
receipts: &[TradeValidationReceiptProjection],
) -> AnyElement {
@@ -12740,120 +12305,6 @@ fn validation_receipt_summary_panel(receipt: &TradeValidationReceiptProjection)
.into_any_element()
}
-fn buyer_receipt_issue_form_section(
- form: &BuyerReceiptIssueFormState,
- cx: &mut Context<HomeView>,
-) -> AnyElement {
- let order_id = form.order_id;
- let submit_action = if form.can_submit(cx) {
- action_button_primary(
- "buyer-order-send-issue",
- app_shared_text(AppTextKey::PersonalOrdersActionSendReceiptIssue),
- cx.listener(move |this, _, _, cx| this.submit_buyer_order_issue_receipt(order_id, cx)),
- cx,
- )
- .into_any_element()
- } else {
- action_button_primary_disabled(
- "buyer-order-send-issue",
- app_shared_text(AppTextKey::PersonalOrdersActionSendReceiptIssue),
- cx,
- )
- .into_any_element()
- };
-
- app_form_section(
- app_shared_text(AppTextKey::PersonalOrdersDetailReceiptLabel),
- app_stack_v(APP_UI_THEME.foundation.spacing.small_px)
- .w_full()
- .child(app_form_input_text(
- AppFormFieldSpec::new(
- app_shared_text(AppTextKey::PersonalOrdersReceiptIssueLabel),
- Option::<SharedString>::None,
- ),
- &form.issue_input,
- false,
- ))
- .child(
- app_cluster(APP_UI_THEME.foundation.spacing.small_px)
- .w_full()
- .child(submit_action)
- .child(action_button_compact(
- "buyer-order-close-issue",
- app_shared_text(AppTextKey::PersonalOrdersActionCloseReceiptIssue),
- cx.listener(|this, _, _, cx| this.close_buyer_receipt_issue_form(cx)),
- cx,
- )),
- ),
- )
- .into_any_element()
-}
-
-fn buyer_receipt_issue_focused_view(
- detail: &BuyerOrderDetailProjection,
- form: &BuyerReceiptIssueFormState,
- cx: &mut Context<HomeView>,
-) -> AnyElement {
- let order_id = form.order_id;
- let submit_action = if form.can_submit(cx) {
- action_button_primary(
- "buyer-order-send-issue",
- app_shared_text(AppTextKey::PersonalOrdersActionSendReceiptIssue),
- cx.listener(move |this, _, _, cx| this.submit_buyer_order_issue_receipt(order_id, cx)),
- cx,
- )
- .into_any_element()
- } else {
- action_button_primary_disabled(
- "buyer-order-send-issue",
- app_shared_text(AppTextKey::PersonalOrdersActionSendReceiptIssue),
- cx,
- )
- .into_any_element()
- };
-
- app_focused_task_view(
- app_shared_text(AppTextKey::PersonalOrdersActionReportIssue),
- app_stack_v(APP_UI_THEME.shells.home_stack_gap_px)
- .w_full()
- .child(app_heading_section(detail.order_number.clone()))
- .child(settings_badge_text(detail.farm_display_name.clone()))
- .child(home_body_text(detail.fulfillment_summary.clone()))
- .child(app_form_input_text(
- AppFormFieldSpec::new(
- app_shared_text(AppTextKey::PersonalOrdersReceiptIssueLabel),
- Option::<SharedString>::None,
- ),
- &form.issue_input,
- false,
- ))
- .child(submit_action),
- text_button(
- "buyer-order-close-issue",
- app_shared_text(AppTextKey::PersonalDetailBackAction),
- cx.listener(|this, _, _, cx| this.close_buyer_receipt_issue_form(cx)),
- cx,
- ),
- )
-}
-
-fn buyer_receipt_actions_available(detail: &BuyerOrderDetailProjection) -> bool {
- detail.workflow.receipt.is_none()
- && detail.workflow.agreement == TradeAgreementStatus::Confirmed
- && matches!(
- detail.workflow.fulfillment,
- Some(TradeFulfillmentStatus::ReadyForPickup | TradeFulfillmentStatus::Delivered)
- )
-}
-
-fn buyer_receipt_status_key(receipt: &TradeReceiptProjection) -> AppTextKey {
- if receipt.received {
- AppTextKey::TradeWorkflowReceiptReceived
- } else {
- AppTextKey::TradeWorkflowReceiptNeedsReview
- }
-}
-
fn validation_receipt_result_key(result: TradeValidationReceiptResult) -> AppTextKey {
match result {
TradeValidationReceiptResult::Valid => AppTextKey::TradeValidationReceiptResultValid,
@@ -12917,7 +12368,6 @@ fn buyer_orders_status_color(status: BuyerOrderStatus) -> u32 {
}
BuyerOrderStatus::Completed
| BuyerOrderStatus::Declined
- | BuyerOrderStatus::Refunded
| BuyerOrderStatus::NeedsReview => APP_UI_THEME.components.app_status_indicator.offline,
}
}
@@ -14109,11 +13559,6 @@ fn orders_table_header() -> impl IntoElement {
false,
))
.child(products_table_header_column(
- AppTextKey::TradeWorkflowAxisPayment,
- Some(128.0),
- false,
- ))
- .child(products_table_header_column(
AppTextKey::OrdersColumnWindow,
Some(160.0),
false,
@@ -14158,9 +13603,6 @@ fn orders_table_row(
.text_color(rgb(APP_UI_THEME.foundation.text.primary))
.child(trade_economics_total_text(&row.workflow.economics)),
)
- .child(div().w(px(128.0)).child(trade_workflow_value_badge(
- trade_payment_display_status_key(row.workflow.payment),
- )))
.child(
div()
.w(px(160.0))
@@ -14184,7 +13626,6 @@ fn orders_table_action(
index: usize,
row: &OrdersListRow,
on_review: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static,
- on_publish_fulfillment: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static,
cx: &App,
) -> AnyElement {
match row.primary_action {
@@ -14195,19 +13636,6 @@ fn orders_table_action(
cx,
)
.into_any_element(),
- Some(
- OrderPrimaryAction::PublishPreparing
- | OrderPrimaryAction::PublishReadyForPickup
- | OrderPrimaryAction::PublishOutForDelivery
- | OrderPrimaryAction::PublishDelivered
- | OrderPrimaryAction::PublishSellerCancelled,
- ) => action_button_compact(
- ("orders-row-action-publish-fulfillment", index),
- app_shared_text(AppTextKey::OrdersActionUpdateFulfillment),
- on_publish_fulfillment,
- cx,
- )
- .into_any_element(),
None => div()
.text_size(px(APP_UI_THEME.foundation.typography.utility_title_text_px))
.text_color(rgb(APP_UI_THEME.foundation.text.secondary))
@@ -14216,26 +13644,6 @@ fn orders_table_action(
}
}
-fn order_detail_fulfillment_action_id(action: OrderFulfillmentAction) -> &'static str {
- match action {
- OrderFulfillmentAction::Preparing => "orders-detail-publish-preparing",
- OrderFulfillmentAction::ReadyForPickup => "orders-detail-publish-ready-for-pickup",
- OrderFulfillmentAction::OutForDelivery => "orders-detail-publish-out-for-delivery",
- OrderFulfillmentAction::Delivered => "orders-detail-publish-delivered",
- OrderFulfillmentAction::SellerCancelled => "orders-detail-publish-seller-cancelled",
- }
-}
-
-fn order_fulfillment_action_label_key(action: OrderFulfillmentAction) -> AppTextKey {
- match action {
- OrderFulfillmentAction::Preparing => AppTextKey::OrdersActionPreparing,
- OrderFulfillmentAction::ReadyForPickup => AppTextKey::OrdersActionReadyForPickup,
- OrderFulfillmentAction::OutForDelivery => AppTextKey::OrdersActionOutForDelivery,
- OrderFulfillmentAction::Delivered => AppTextKey::OrdersActionMarkDelivered,
- OrderFulfillmentAction::SellerCancelled => AppTextKey::OrdersActionCancelFulfillment,
- }
-}
-
fn orders_empty_state_card(filter: OrdersFilter) -> impl IntoElement {
let (title_key, body_key) = if filter == OrdersFilter::NeedsAction {
(
@@ -14255,24 +13663,21 @@ fn orders_status_color(status: OrderStatus) -> u32 {
OrderStatus::Scheduled | OrderStatus::Packed => {
APP_UI_THEME.components.app_status_indicator.online
}
- OrderStatus::Completed
- | OrderStatus::Declined
- | OrderStatus::Refunded
- | OrderStatus::NeedsReview => APP_UI_THEME.components.app_status_indicator.offline,
+ OrderStatus::Completed | OrderStatus::Declined | OrderStatus::NeedsReview => {
+ APP_UI_THEME.components.app_status_indicator.offline
+ }
}
}
fn order_recovery_title_key(kind: RecoveryKind) -> AppTextKey {
match kind {
RecoveryKind::MissedPickup => AppTextKey::OrdersRecoveryMissedPickupTitle,
- RecoveryKind::RefundFollowUp => AppTextKey::OrdersRecoveryRefundFollowUpTitle,
}
}
fn order_recovery_empty_body_key(kind: RecoveryKind) -> AppTextKey {
match kind {
RecoveryKind::MissedPickup => AppTextKey::OrdersRecoveryMissedPickupBody,
- RecoveryKind::RefundFollowUp => AppTextKey::OrdersRecoveryRefundFollowUpBody,
}
}
@@ -14304,7 +13709,6 @@ fn order_recovery_state_badge(state: RecoveryState) -> AnyElement {
fn order_recovery_kind_index(kind: RecoveryKind) -> usize {
match kind {
RecoveryKind::MissedPickup => 0,
- RecoveryKind::RefundFollowUp => 1,
}
}
@@ -17205,8 +16609,7 @@ mod tests {
about_conflict_review_body_key, about_manual_refresh_enabled, about_runtime_rows,
about_status_rows, account_display_name, app_text,
buyer_order_coordination_notice_forces_redraw, buyer_order_detail_focus_after_open,
- buyer_orders_retry_action_visible, buyer_receipt_issue_focus_after_submit,
- buyer_receipt_status_key, farm_setup_onboarding_card_spec, farmer_home_farm_state,
+ buyer_orders_retry_action_visible, farm_setup_onboarding_card_spec, farmer_home_farm_state,
farmer_order_detail_focus_after_open, farmer_pack_day_available, home_auto_focus_target,
home_content_scroll_id, home_saved_farm, home_sidebar_navigation_sections, home_stage,
home_window_launch_size_px, home_window_minimum_size_px,
@@ -17223,8 +16626,8 @@ mod tests {
startup_issue_summary_text, startup_notice_text, startup_signer_preview_summary,
startup_signer_preview_summary_for_connect_state, startup_signer_source_input_is_editable,
startup_signer_status_spec, startup_signer_transport_failure_requires_notice,
- trade_agreement_status_key, trade_fulfillment_status_key, trade_inventory_status_key,
- trade_payment_display_status_key, trade_revision_status_key, trade_workflow_source_key,
+ trade_agreement_status_key, trade_inventory_status_key, trade_revision_status_key,
+ trade_workflow_source_key,
};
use crate::runtime::{
DesktopAppRuntimeMetadataSummary, DesktopAppRuntimeSummary, DesktopAppSdkDiagnosticsState,
@@ -17256,17 +16659,16 @@ mod tests {
BuyerOrderStatus, BuyerOrdersListRow, FarmId, FarmOrderMethod, FarmReadiness,
FarmSetupDraft, FarmSetupProjection, FarmSummary, FarmerSection, FulfillmentWindowId,
FulfillmentWindowSummary, LoggedOutStartupPhase, LoggedOutStartupProjection,
- OrderDetailProjection, OrderFulfillmentAction, OrderId, OrderPrimaryAction, OrderStatus,
- OrdersListRow, PackDayBatchPrintArtifact, PackDayBatchPrintFailureKind,
- PackDayExportArtifact, PackDayExportArtifactKind, PackDayExportBundle,
- PackDayHostHandoffKind, PackDayHostHandoffStatus, PackDayPrintFailureKind,
- PackDayPrintKind, PackDayPrintStatus, PackDayProductTotalRow, PackDayProjection,
- PersonalSection, ProductId, ReminderDeadlineProjection, ReminderDeliveryState, ReminderId,
- ReminderKind, ReminderSurface, ReminderUrgency, RepeatDemandEligibility,
- RepeatDemandHandoffProjection, ShellSection, TodayAgendaProjection, TodaySetupTask,
- TodaySetupTaskKind, TradeAgreementStatus, TradeEconomicsProjection, TradeFulfillmentStatus,
- TradeInventoryStatus, TradePaymentDisplayStatus, TradeReceiptProjection,
- TradeRevisionStatus, TradeWorkflowProjection, TradeWorkflowSource,
+ OrderDetailProjection, OrderId, OrderStatus, OrdersListRow, PackDayBatchPrintArtifact,
+ PackDayBatchPrintFailureKind, PackDayExportArtifact, PackDayExportArtifactKind,
+ PackDayExportBundle, PackDayHostHandoffKind, PackDayHostHandoffStatus,
+ PackDayPrintFailureKind, PackDayPrintKind, PackDayPrintStatus, PackDayProductTotalRow,
+ PackDayProjection, PersonalSection, ProductId, ReminderDeadlineProjection,
+ ReminderDeliveryState, ReminderId, ReminderKind, ReminderSurface, ReminderUrgency,
+ RepeatDemandEligibility, RepeatDemandHandoffProjection, ShellSection,
+ TodayAgendaProjection, TodaySetupTask, TodaySetupTaskKind, TradeAgreementStatus,
+ TradeEconomicsProjection, TradeInventoryStatus, TradeRevisionStatus,
+ TradeWorkflowProjection, TradeWorkflowSource,
};
use radroots_identity::RadrootsIdentity;
use std::{
@@ -17420,7 +16822,6 @@ mod tests {
status: BuyerOrderStatus::Placed,
items: Vec::new(),
economics: TradeEconomicsProjection::default(),
- payment: TradePaymentDisplayStatus::NotRecorded,
workflow: TradeWorkflowProjection::from_buyer_order_status(
order_id,
BuyerOrderStatus::Placed,
@@ -17466,11 +16867,9 @@ mod tests {
pickup_location_label: None,
items: Vec::new(),
economics: TradeEconomicsProjection::default(),
- payment: TradePaymentDisplayStatus::NotRecorded,
workflow: TradeWorkflowProjection::from_order_status(order_id, OrderStatus::Scheduled),
validation_receipts: Vec::new(),
- primary_action: Some(OrderPrimaryAction::PublishPreparing),
- fulfillment_actions: OrderFulfillmentAction::ALL.to_vec(),
+ primary_action: None,
recoveries: Vec::new(),
});
@@ -17485,20 +16884,6 @@ mod tests {
}
#[test]
- fn buyer_receipt_issue_submit_returns_to_order_detail() {
- let order_id = OrderId::new();
-
- assert_eq!(
- buyer_receipt_issue_focus_after_submit(true, order_id),
- Some(HomeFocusedView::BuyerOrderDetail(order_id))
- );
- assert_eq!(
- buyer_receipt_issue_focus_after_submit(false, order_id),
- None
- );
- }
-
- #[test]
fn buyer_browse_refresh_failure_uses_typed_visible_notice() {
let (mut view, paths, home_dir) = test_home_view("buyer_notice");
block_shared_local_events_database(&paths);
@@ -17711,10 +17096,6 @@ mod tests {
AppTextKey::TradeWorkflowAgreementCancelled,
),
(
- TradeAgreementStatus::Completed,
- AppTextKey::TradeWorkflowAgreementCompleted,
- ),
- (
TradeAgreementStatus::NeedsReview,
AppTextKey::TradeWorkflowAgreementNeedsReview,
),
@@ -17747,36 +17128,6 @@ mod tests {
for (status, key) in [
(
- TradeFulfillmentStatus::Confirmed,
- AppTextKey::TradeWorkflowFulfillmentConfirmed,
- ),
- (
- TradeFulfillmentStatus::Preparing,
- AppTextKey::TradeWorkflowFulfillmentPreparing,
- ),
- (
- TradeFulfillmentStatus::ReadyForPickup,
- AppTextKey::TradeWorkflowFulfillmentReadyForPickup,
- ),
- (
- TradeFulfillmentStatus::OutForDelivery,
- AppTextKey::TradeWorkflowFulfillmentOutForDelivery,
- ),
- (
- TradeFulfillmentStatus::Delivered,
- AppTextKey::TradeWorkflowFulfillmentDelivered,
- ),
- (
- TradeFulfillmentStatus::Cancelled,
- AppTextKey::TradeWorkflowFulfillmentCancelled,
- ),
- ] {
- assert_eq!(trade_fulfillment_status_key(status), key);
- assert!(!app_text(key).is_empty());
- }
-
- for (status, key) in [
- (
TradeInventoryStatus::Available,
AppTextKey::TradeWorkflowInventoryAvailable,
),
@@ -17797,56 +17148,6 @@ mod tests {
assert!(!app_text(key).is_empty());
}
- for (status, key) in [
- (
- TradePaymentDisplayStatus::NotRecorded,
- AppTextKey::TradeWorkflowPaymentNotRecorded,
- ),
- (
- TradePaymentDisplayStatus::Pending,
- AppTextKey::TradeWorkflowPaymentPending,
- ),
- (
- TradePaymentDisplayStatus::Recorded,
- AppTextKey::TradeWorkflowPaymentRecorded,
- ),
- (
- TradePaymentDisplayStatus::Settled,
- AppTextKey::TradeWorkflowPaymentSettled,
- ),
- (
- TradePaymentDisplayStatus::NeedsReview,
- AppTextKey::TradeWorkflowPaymentNeedsReview,
- ),
- ] {
- assert_eq!(trade_payment_display_status_key(status), key);
- assert!(!app_text(key).is_empty());
- }
-
- for (receipt, key) in [
- (
- TradeReceiptProjection {
- event_id: "receipt-clean".to_owned(),
- received: true,
- issue: None,
- received_at: 1_774_000_030,
- },
- AppTextKey::TradeWorkflowReceiptReceived,
- ),
- (
- TradeReceiptProjection {
- event_id: "receipt-issue".to_owned(),
- received: false,
- issue: Some("items need review".to_owned()),
- received_at: 1_774_000_031,
- },
- AppTextKey::TradeWorkflowReceiptNeedsReview,
- ),
- ] {
- assert_eq!(buyer_receipt_status_key(&receipt), key);
- assert!(!app_text(key).is_empty());
- }
-
for (source, key) in [
(
TradeWorkflowSource::App,
@@ -17875,35 +17176,6 @@ mod tests {
}
#[test]
- fn trade_payment_display_status_keys_cover_passive_states() {
- for (status, key) in [
- (
- TradePaymentDisplayStatus::NotRecorded,
- AppTextKey::TradeWorkflowPaymentNotRecorded,
- ),
- (
- TradePaymentDisplayStatus::Pending,
- AppTextKey::TradeWorkflowPaymentPending,
- ),
- (
- TradePaymentDisplayStatus::Recorded,
- AppTextKey::TradeWorkflowPaymentRecorded,
- ),
- (
- TradePaymentDisplayStatus::Settled,
- AppTextKey::TradeWorkflowPaymentSettled,
- ),
- (
- TradePaymentDisplayStatus::NeedsReview,
- AppTextKey::TradeWorkflowPaymentNeedsReview,
- ),
- ] {
- assert_eq!(trade_payment_display_status_key(status), key);
- assert!(!app_text(key).is_empty());
- }
- }
-
- #[test]
fn today_route_has_no_setup_onboarding_card() {
assert!(farm_setup_onboarding_card_spec(HomeRoute::Today).is_none());
}
@@ -18126,7 +17398,6 @@ mod tests {
status: BuyerOrderStatus::Placed,
items: Vec::new(),
economics: TradeEconomicsProjection::default(),
- payment: TradePaymentDisplayStatus::NotRecorded,
workflow: TradeWorkflowProjection::from_buyer_order_status(
order_id,
BuyerOrderStatus::Placed,
@@ -18145,16 +17416,6 @@ mod tests {
home_auto_focus_target(&buyer_orders, HomeAutoFocusState::default()),
Some(HomeAutoFocusTarget::BuyerOrderRepeatDemand)
);
- assert_eq!(
- home_auto_focus_target(
- &buyer_orders,
- HomeAutoFocusState {
- has_buyer_receipt_issue_form: true,
- ..HomeAutoFocusState::default()
- },
- ),
- Some(HomeAutoFocusTarget::BuyerReceiptIssueInput)
- );
}
#[test]
@@ -18261,8 +17522,7 @@ mod tests {
farmer_order_id,
OrderStatus::Scheduled,
),
- primary_action: Some(OrderPrimaryAction::PublishPreparing),
- fulfillment_actions: OrderFulfillmentAction::ALL.to_vec(),
+ primary_action: None,
}];
orders.orders_projection.detail = Some(OrderDetailProjection {
order_id: farmer_order_id,
@@ -18275,19 +17535,17 @@ mod tests {
pickup_location_label: None,
items: Vec::new(),
economics: TradeEconomicsProjection::default(),
- payment: TradePaymentDisplayStatus::NotRecorded,
workflow: TradeWorkflowProjection::from_order_status(
farmer_order_id,
OrderStatus::Scheduled,
),
validation_receipts: Vec::new(),
- primary_action: Some(OrderPrimaryAction::PublishPreparing),
- fulfillment_actions: OrderFulfillmentAction::ALL.to_vec(),
+ primary_action: None,
recoveries: Vec::new(),
});
assert_eq!(
home_auto_focus_target(&orders, HomeAutoFocusState::default()),
- Some(HomeAutoFocusTarget::OrdersDetailPublishFulfillmentFirst)
+ Some(HomeAutoFocusTarget::OrdersRowOpenFirst)
);
}
diff --git a/crates/i18n/src/keys.rs b/crates/i18n/src/keys.rs
@@ -333,19 +333,11 @@ define_app_text_keys! {
PersonalOrdersDetailStatusLabel => "personal.orders.detail.status.label",
PersonalOrdersDetailFulfillmentLabel => "personal.orders.detail.fulfillment.label",
PersonalOrdersDetailTotalLabel => "personal.orders.detail.total.label",
- PersonalOrdersDetailPaymentLabel => "personal.orders.detail.payment.label",
PersonalOrdersDetailNoteLabel => "personal.orders.detail.note.label",
- PersonalOrdersDetailReceiptLabel => "personal.orders.detail.receipt.label",
PersonalOrdersDetailItemsTitle => "personal.orders.detail.items.title",
PersonalOrdersActionCancel => "personal.orders.action.cancel",
PersonalOrdersActionAcceptChange => "personal.orders.action.accept_change",
PersonalOrdersActionKeepOrder => "personal.orders.action.keep_order",
- PersonalOrdersActionMarkReceived => "personal.orders.action.mark_received",
- PersonalOrdersActionReportIssue => "personal.orders.action.report_issue",
- PersonalOrdersActionSendReceiptIssue => "personal.orders.action.send_receipt_issue",
- PersonalOrdersActionCloseReceiptIssue => "personal.orders.action.close_receipt_issue",
- PersonalOrdersReceiptIssueLabel => "personal.orders.receipt.issue.label",
- PersonalOrdersReceiptIssuePlaceholder => "personal.orders.receipt.issue.placeholder",
PersonalOrdersRepeatDemandTitle => "personal.orders.repeat_demand.title",
PersonalOrdersRepeatDemandActionEligible => "personal.orders.repeat_demand.action.eligible",
PersonalOrdersRepeatDemandActionPartial => "personal.orders.repeat_demand.action.partial",
@@ -360,7 +352,6 @@ define_app_text_keys! {
PersonalOrdersStatusReady => "personal.orders.status.ready",
PersonalOrdersStatusCompleted => "personal.orders.status.completed",
PersonalOrdersStatusDeclined => "personal.orders.status.declined",
- PersonalOrdersStatusRefunded => "personal.orders.status.refunded",
PersonalOrdersStatusNeedsReview => "personal.orders.status.needs_review",
PersonalCartSurfaceBody => "personal.cart.surface.body",
PersonalOrderSummaryTitle => "personal.order_summary.title",
@@ -398,7 +389,6 @@ define_app_text_keys! {
OrdersStatusInHandoff => "orders.status.in_handoff",
OrdersStatusCompleted => "orders.status.completed",
OrdersStatusDeclined => "orders.status.declined",
- OrdersStatusRefunded => "orders.status.refunded",
OrdersStatusNeedsReview => "orders.status.needs_review",
OrdersTableTitle => "orders.table.title",
OrdersColumnOrder => "orders.column.order",
@@ -407,12 +397,6 @@ define_app_text_keys! {
OrdersColumnPickup => "orders.column.pickup",
OrdersColumnAction => "orders.column.action",
OrdersActionReview => "orders.action.review",
- OrdersActionPreparing => "orders.action.preparing",
- OrdersActionReadyForPickup => "orders.action.ready_for_pickup",
- OrdersActionOutForDelivery => "orders.action.out_for_delivery",
- OrdersActionMarkDelivered => "orders.action.mark_delivered",
- OrdersActionCancelFulfillment => "orders.action.cancel_fulfillment",
- OrdersActionUpdateFulfillment => "orders.action.update_fulfillment",
OrdersEmptyTitle => "orders.empty.title",
OrdersEmptyBody => "orders.empty.body",
OrdersEmptyNeedsActionTitle => "orders.empty.needs_action.title",
@@ -447,8 +431,6 @@ define_app_text_keys! {
OrdersRecoverySectionTitle => "orders.recovery.section.title",
OrdersRecoveryMissedPickupTitle => "orders.recovery.missed_pickup.title",
OrdersRecoveryMissedPickupBody => "orders.recovery.missed_pickup.body",
- OrdersRecoveryRefundFollowUpTitle => "orders.recovery.refund_follow_up.title",
- OrdersRecoveryRefundFollowUpBody => "orders.recovery.refund_follow_up.body",
OrdersRecoveryLastUpdatedLabel => "orders.recovery.last_updated.label",
OrdersRecoveryActionOpenFollowUp => "orders.recovery.action.open_follow_up",
OrdersRecoveryActionStartReview => "orders.recovery.action.start_review",
@@ -459,38 +441,21 @@ define_app_text_keys! {
OrdersRecoveryStateResolved => "orders.recovery.state.resolved",
TradeWorkflowAxisAgreement => "trade.workflow.axis.agreement",
TradeWorkflowAxisRevision => "trade.workflow.axis.revision",
- TradeWorkflowAxisFulfillment => "trade.workflow.axis.fulfillment",
TradeWorkflowAxisInventory => "trade.workflow.axis.inventory",
- TradeWorkflowAxisPayment => "trade.workflow.axis.payment",
- TradeWorkflowAxisReceipt => "trade.workflow.axis.receipt",
TradeWorkflowAxisSource => "trade.workflow.axis.source",
TradeWorkflowAgreementOrdered => "trade.workflow.agreement.ordered",
TradeWorkflowAgreementConfirmed => "trade.workflow.agreement.confirmed",
TradeWorkflowAgreementDeclined => "trade.workflow.agreement.declined",
TradeWorkflowAgreementCancelled => "trade.workflow.agreement.cancelled",
- TradeWorkflowAgreementCompleted => "trade.workflow.agreement.completed",
TradeWorkflowAgreementNeedsReview => "trade.workflow.agreement.needs_review",
TradeWorkflowRevisionNone => "trade.workflow.revision.none",
TradeWorkflowRevisionChangeProposed => "trade.workflow.revision.change_proposed",
TradeWorkflowRevisionUpdated => "trade.workflow.revision.updated",
TradeWorkflowRevisionKeptAsPlaced => "trade.workflow.revision.kept_as_placed",
- TradeWorkflowFulfillmentConfirmed => "trade.workflow.fulfillment.confirmed",
- TradeWorkflowFulfillmentPreparing => "trade.workflow.fulfillment.preparing",
- TradeWorkflowFulfillmentReadyForPickup => "trade.workflow.fulfillment.ready_for_pickup",
- TradeWorkflowFulfillmentOutForDelivery => "trade.workflow.fulfillment.out_for_delivery",
- TradeWorkflowFulfillmentDelivered => "trade.workflow.fulfillment.delivered",
- TradeWorkflowFulfillmentCancelled => "trade.workflow.fulfillment.cancelled",
TradeWorkflowInventoryAvailable => "trade.workflow.inventory.available",
TradeWorkflowInventoryReserved => "trade.workflow.inventory.reserved",
TradeWorkflowInventorySoldOut => "trade.workflow.inventory.sold_out",
TradeWorkflowInventoryNeedsReview => "trade.workflow.inventory.needs_review",
- TradeWorkflowPaymentNotRecorded => "trade.workflow.payment.not_recorded",
- TradeWorkflowPaymentPending => "trade.workflow.payment.pending",
- TradeWorkflowPaymentRecorded => "trade.workflow.payment.recorded",
- TradeWorkflowPaymentSettled => "trade.workflow.payment.settled",
- TradeWorkflowPaymentNeedsReview => "trade.workflow.payment.needs_review",
- TradeWorkflowReceiptReceived => "trade.workflow.receipt.received",
- TradeWorkflowReceiptNeedsReview => "trade.workflow.receipt.needs_review",
TradeWorkflowProvenanceApp => "trade.workflow.provenance.app",
TradeWorkflowProvenanceCli => "trade.workflow.provenance.cli",
TradeWorkflowProvenanceRelay => "trade.workflow.provenance.relay",
diff --git a/crates/i18n/src/lib.rs b/crates/i18n/src/lib.rs
@@ -492,27 +492,6 @@ mod tests {
app_text(AppTextKey::OrdersStatusNeedsReview),
"Needs review"
);
- assert_eq!(
- app_text(AppTextKey::OrdersActionReadyForPickup),
- "Ready for pickup"
- );
- assert_eq!(app_text(AppTextKey::OrdersActionPreparing), "Preparing");
- assert_eq!(
- app_text(AppTextKey::OrdersActionOutForDelivery),
- "Out for delivery"
- );
- assert_eq!(
- app_text(AppTextKey::OrdersActionMarkDelivered),
- "Mark delivered"
- );
- assert_eq!(
- app_text(AppTextKey::OrdersActionCancelFulfillment),
- "Cancel fulfillment"
- );
- assert_eq!(
- app_text(AppTextKey::OrdersActionUpdateFulfillment),
- "Update"
- );
assert_eq!(app_text(AppTextKey::OrdersDetailTitle), "Order detail");
assert_eq!(app_text(AppTextKey::OrdersRecoverySectionTitle), "Recovery");
assert_eq!(
@@ -520,14 +499,6 @@ mod tests {
"Missed pickup"
);
assert_eq!(
- app_text(AppTextKey::OrdersRecoveryRefundFollowUpTitle),
- "Payment status"
- );
- assert_eq!(
- app_text(AppTextKey::OrdersRecoveryRefundFollowUpBody),
- "Track the recorded payment state for this order."
- );
- assert_eq!(
app_text(AppTextKey::OrdersRecoveryActionResolve),
"Mark resolved"
);
@@ -674,12 +645,6 @@ mod tests {
app_text(AppTextKey::TradeWorkflowAxisAgreement),
"Agreement"
);
- assert_eq!(
- app_text(AppTextKey::TradeWorkflowAxisFulfillment),
- "Fulfillment"
- );
- assert_eq!(app_text(AppTextKey::TradeWorkflowAxisPayment), "Payment");
- assert_eq!(app_text(AppTextKey::TradeWorkflowAxisReceipt), "Receipt");
assert_eq!(app_text(AppTextKey::TradeWorkflowAxisSource), "Source");
assert_eq!(
app_text(AppTextKey::TradeWorkflowAgreementOrdered),
@@ -702,31 +667,9 @@ mod tests {
"Kept as placed"
);
assert_eq!(
- app_text(AppTextKey::TradeWorkflowFulfillmentReadyForPickup),
- "Ready for pickup"
- );
- assert_eq!(
app_text(AppTextKey::TradeWorkflowInventoryReserved),
"Reserved"
);
- assert_eq!(
- app_text(AppTextKey::TradeWorkflowPaymentNotRecorded),
- "Not recorded"
- );
- assert_eq!(app_text(AppTextKey::TradeWorkflowPaymentPending), "Pending");
- assert_eq!(
- app_text(AppTextKey::TradeWorkflowPaymentRecorded),
- "Recorded"
- );
- assert_eq!(app_text(AppTextKey::TradeWorkflowPaymentSettled), "Settled");
- assert_eq!(
- app_text(AppTextKey::TradeWorkflowReceiptReceived),
- "Received"
- );
- assert_eq!(
- app_text(AppTextKey::TradeWorkflowReceiptNeedsReview),
- "Needs review"
- );
assert_eq!(app_text(AppTextKey::TradeWorkflowProvenanceCli), "CLI");
assert_eq!(
app_text(AppTextKey::TradeWorkflowProvenanceLocalEvents),
@@ -734,20 +677,6 @@ mod tests {
);
}
- #[test]
- fn payment_workflow_copy_covers_passive_statuses() {
- for (key, expected) in [
- (AppTextKey::TradeWorkflowPaymentNotRecorded, "Not recorded"),
- (AppTextKey::TradeWorkflowPaymentPending, "Pending"),
- (AppTextKey::TradeWorkflowPaymentRecorded, "Recorded"),
- (AppTextKey::TradeWorkflowPaymentSettled, "Settled"),
- (AppTextKey::TradeWorkflowPaymentNeedsReview, "Needs review"),
- ] {
- assert_eq!(app_text(key), expected);
- }
- }
-
- #[test]
fn validation_receipt_copy_covers_passive_evidence() {
for (key, expected) in [
(AppTextKey::TradeValidationReceiptSectionLabel, "Validation"),
@@ -843,10 +772,6 @@ mod tests {
"Declined"
);
assert_eq!(
- app_text(AppTextKey::PersonalOrdersStatusRefunded),
- "Refunded"
- );
- assert_eq!(
app_text(AppTextKey::PersonalOrdersStatusNeedsReview),
"Needs review"
);
@@ -867,10 +792,6 @@ mod tests {
"Order note"
);
assert_eq!(
- app_text(AppTextKey::PersonalOrdersDetailReceiptLabel),
- "Receipt"
- );
- assert_eq!(
app_text(AppTextKey::PersonalOrdersActionCancel),
"Cancel order"
);
@@ -883,22 +804,6 @@ mod tests {
"Keep order"
);
assert_eq!(
- app_text(AppTextKey::PersonalOrdersActionMarkReceived),
- "Mark received"
- );
- assert_eq!(
- app_text(AppTextKey::PersonalOrdersActionReportIssue),
- "Report issue"
- );
- assert_eq!(
- app_text(AppTextKey::PersonalOrdersActionSendReceiptIssue),
- "Send update"
- );
- assert_eq!(
- app_text(AppTextKey::PersonalOrdersReceiptIssuePlaceholder),
- "What needs review"
- );
- assert_eq!(
app_text(AppTextKey::PersonalOrdersRepeatDemandTitle),
"Reorder"
);
diff --git a/crates/runtime/src/lib.rs b/crates/runtime/src/lib.rs
@@ -39,15 +39,13 @@ pub use sdk::{
APP_SDK_DEFAULT_COMMAND_QUEUE_CAPACITY, APP_SDK_STORAGE_DIR_NAME, AppSdkConfig,
AppSdkDiagnostics, AppSdkEventStoreDiagnostics, AppSdkFarmPublishRequest,
AppSdkIntegrityDiagnostics, AppSdkLifecycleState, AppSdkListingPublishRequest,
- AppSdkOrderCancellationRequest, AppSdkOrderDecisionRequest,
- AppSdkOrderFulfillmentUpdateRequest, AppSdkOrderReceiptRecordRequest,
- AppSdkOrderRevisionDecisionRequest, AppSdkOrderRevisionProposalRequest,
- AppSdkOrderSubmitRequest, AppSdkOutboxDiagnostics, AppSdkProjectionLifecycleState,
- AppSdkProjectionLifecycleStatus, AppSdkRelayUrlPolicy, AppSdkRestorePreflightReceipt,
- AppSdkRestorePreflightRequest, AppSdkRuntime, AppSdkRuntimeError, AppSdkRuntimeIssue,
- AppSdkRuntimeStatus, AppSdkSqliteStoreDiagnostics, AppSdkStorageDiagnostics,
- AppSdkStoragePaths, AppSdkSyncDiagnostics, AppSdkSyncEventStoreDiagnostics,
- AppSdkSyncOutboxDiagnostics, AppSdkSyncRelayTargetDiagnostics, AppSdkWorkflowReceipt,
- app_sdk_storage_root_from_data_root,
+ AppSdkOrderCancellationRequest, AppSdkOrderDecisionRequest, AppSdkOrderRevisionDecisionRequest,
+ AppSdkOrderRevisionProposalRequest, AppSdkOrderSubmitRequest, AppSdkOutboxDiagnostics,
+ AppSdkProjectionLifecycleState, AppSdkProjectionLifecycleStatus, AppSdkRelayUrlPolicy,
+ AppSdkRestorePreflightReceipt, AppSdkRestorePreflightRequest, AppSdkRuntime,
+ AppSdkRuntimeError, AppSdkRuntimeIssue, AppSdkRuntimeStatus, AppSdkSqliteStoreDiagnostics,
+ AppSdkStorageDiagnostics, AppSdkStoragePaths, AppSdkSyncDiagnostics,
+ AppSdkSyncEventStoreDiagnostics, AppSdkSyncOutboxDiagnostics, AppSdkSyncRelayTargetDiagnostics,
+ AppSdkWorkflowReceipt, app_sdk_storage_root_from_data_root,
};
pub use startup::{AppStartupEvent, AppStartupEventMetadata, launch_startup_event};
diff --git a/crates/runtime/src/sdk.rs b/crates/runtime/src/sdk.rs
@@ -17,9 +17,8 @@ use radroots_events::{
farm::RadrootsFarm,
listing::RadrootsListing,
order::{
- RadrootsOrderCancellation, RadrootsOrderDecision, RadrootsOrderFulfillmentUpdate,
- RadrootsOrderReceipt, RadrootsOrderRequest, RadrootsOrderRevisionDecision,
- RadrootsOrderRevisionProposal,
+ RadrootsOrderCancellation, RadrootsOrderDecision, RadrootsOrderRequest,
+ RadrootsOrderRevisionDecision, RadrootsOrderRevisionProposal,
},
};
use radroots_nostr::prelude::RadrootsNostrKeys;
@@ -27,17 +26,15 @@ use radroots_sdk::{
FARM_PUBLISH_OPERATION_KIND, FarmEnqueuePublishRequest, FarmEnqueueReceipt, IntegrityReceipt,
IntegrityRequest, LISTING_PUBLISH_OPERATION_KIND, ListingEnqueuePublishRequest,
ListingEnqueueReceipt, ORDER_CANCELLATION_OPERATION_KIND, ORDER_DECISION_OPERATION_KIND,
- ORDER_FULFILLMENT_UPDATE_OPERATION_KIND, ORDER_RECEIPT_RECORD_OPERATION_KIND,
ORDER_REVISION_DECISION_OPERATION_KIND, ORDER_REVISION_PROPOSAL_OPERATION_KIND,
ORDER_SUBMIT_OPERATION_KIND, OrderCancellationEnqueueRequest, OrderCancellationReceipt,
OrderDecisionEnqueueRequest, OrderDecisionReceipt, OrderEvidenceIngestRequest,
- OrderFulfillmentUpdateEnqueueRequest, OrderFulfillmentUpdateReceipt,
- OrderReceiptRecordEnqueueRequest, OrderReceiptRecordReceipt, OrderRequestEvidenceIngestRequest,
- OrderRevisionDecisionEnqueueRequest, OrderRevisionDecisionReceipt,
- OrderRevisionProposalEnqueueRequest, OrderRevisionProposalReceipt, OrderSubmitEnqueueRequest,
- OrderSubmitReceipt, RadrootsSdk, RadrootsSdkError, RadrootsSdkStoragePaths, RestoreReceipt,
- RestoreRequest, SdkBackupVerification, SdkRelayUrlPolicy as SdkRuntimeRelayUrlPolicy,
- StorageStatusReceipt, StorageStatusRequest, SyncStatusReceipt, SyncStatusRequest,
+ OrderRequestEvidenceIngestRequest, OrderRevisionDecisionEnqueueRequest,
+ OrderRevisionDecisionReceipt, OrderRevisionProposalEnqueueRequest,
+ OrderRevisionProposalReceipt, OrderSubmitEnqueueRequest, OrderSubmitReceipt, RadrootsSdk,
+ RadrootsSdkError, RadrootsSdkStoragePaths, RestoreReceipt, RestoreRequest,
+ SdkBackupVerification, SdkRelayUrlPolicy as SdkRuntimeRelayUrlPolicy, StorageStatusReceipt,
+ StorageStatusRequest, SyncStatusReceipt, SyncStatusRequest,
};
use radroots_sdk::{SdkMutationState, SdkRelayTargetPolicy};
use serde::Serialize;
@@ -288,32 +285,6 @@ pub struct AppSdkOrderCancellationRequest {
pub idempotency_key: Option<String>,
}
-pub struct AppSdkOrderFulfillmentUpdateRequest {
- pub actor_account_id: String,
- pub actor_pubkey: String,
- pub signer_keys: RadrootsNostrKeys,
- pub evidence_events: Vec<RadrootsNostrEvent>,
- pub root_event: RadrootsNostrEventPtr,
- pub previous_event: RadrootsNostrEventPtr,
- pub fulfillment: RadrootsOrderFulfillmentUpdate,
- pub target_relays: Vec<String>,
- pub relay_url_policy: AppSdkRelayUrlPolicy,
- pub idempotency_key: Option<String>,
-}
-
-pub struct AppSdkOrderReceiptRecordRequest {
- pub actor_account_id: String,
- pub actor_pubkey: String,
- pub signer_keys: RadrootsNostrKeys,
- pub evidence_events: Vec<RadrootsNostrEvent>,
- pub root_event: RadrootsNostrEventPtr,
- pub previous_event: RadrootsNostrEventPtr,
- pub receipt: RadrootsOrderReceipt,
- pub target_relays: Vec<String>,
- pub relay_url_policy: AppSdkRelayUrlPolicy,
- pub idempotency_key: Option<String>,
-}
-
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct AppSdkWorkflowReceipt {
pub operation_kind: String,
@@ -434,14 +405,6 @@ enum AppSdkWorkerCommand {
AppSdkOrderCancellationRequest,
mpsc::Sender<Result<AppSdkWorkflowReceipt, AppSdkRuntimeIssue>>,
),
- EnqueueOrderFulfillmentUpdate(
- AppSdkOrderFulfillmentUpdateRequest,
- mpsc::Sender<Result<AppSdkWorkflowReceipt, AppSdkRuntimeIssue>>,
- ),
- EnqueueOrderReceiptRecord(
- AppSdkOrderReceiptRecordRequest,
- mpsc::Sender<Result<AppSdkWorkflowReceipt, AppSdkRuntimeIssue>>,
- ),
BeginProjectionRebuild(
mpsc::Sender<Result<AppSdkProjectionLifecycleStatus, AppSdkRuntimeIssue>>,
),
@@ -469,12 +432,6 @@ impl fmt::Debug for AppSdkWorkerCommand {
formatter.write_str("EnqueueOrderRevisionDecision")
}
Self::EnqueueOrderCancellation(_, _) => formatter.write_str("EnqueueOrderCancellation"),
- Self::EnqueueOrderFulfillmentUpdate(_, _) => {
- formatter.write_str("EnqueueOrderFulfillmentUpdate")
- }
- Self::EnqueueOrderReceiptRecord(_, _) => {
- formatter.write_str("EnqueueOrderReceiptRecord")
- }
Self::BeginProjectionRebuild(_) => formatter.write_str("BeginProjectionRebuild"),
Self::CompleteProjectionRebuild(_) => formatter.write_str("CompleteProjectionRebuild"),
}
@@ -659,24 +616,6 @@ impl AppSdkRuntime {
})
}
- pub fn enqueue_order_fulfillment_update(
- &self,
- request: AppSdkOrderFulfillmentUpdateRequest,
- ) -> Result<AppSdkWorkflowReceipt, AppSdkRuntimeError> {
- self.run_command(|response_sender| {
- AppSdkWorkerCommand::EnqueueOrderFulfillmentUpdate(request, response_sender)
- })
- }
-
- pub fn enqueue_order_receipt_record(
- &self,
- request: AppSdkOrderReceiptRecordRequest,
- ) -> Result<AppSdkWorkflowReceipt, AppSdkRuntimeError> {
- self.run_command(|response_sender| {
- AppSdkWorkerCommand::EnqueueOrderReceiptRecord(request, response_sender)
- })
- }
-
pub fn begin_projection_rebuild(
&self,
) -> Result<AppSdkProjectionLifecycleStatus, AppSdkRuntimeError> {
@@ -1223,30 +1162,6 @@ fn run_app_sdk_worker(
};
send_worker_result(&shared, response_sender, result);
}
- AppSdkWorkerCommand::EnqueueOrderFulfillmentUpdate(request, response_sender) => {
- let result = if let Some(issue) = lifecycle_busy_issue(&shared) {
- Err(issue)
- } else {
- match sdk.as_ref() {
- Some(sdk) => {
- enqueue_order_fulfillment_update_with_sdk(&runtime, sdk, request)
- }
- None => Err(runtime_unavailable_issue(&shared)),
- }
- };
- send_worker_result(&shared, response_sender, result);
- }
- AppSdkWorkerCommand::EnqueueOrderReceiptRecord(request, response_sender) => {
- let result = if let Some(issue) = lifecycle_busy_issue(&shared) {
- Err(issue)
- } else {
- match sdk.as_ref() {
- Some(sdk) => enqueue_order_receipt_record_with_sdk(&runtime, sdk, request),
- None => Err(runtime_unavailable_issue(&shared)),
- }
- };
- send_worker_result(&shared, response_sender, result);
- }
AppSdkWorkerCommand::BeginProjectionRebuild(response_sender) => {
let result = match sdk.as_ref() {
Some(_) => Ok(begin_projection_rebuild(&shared)),
@@ -1363,20 +1278,6 @@ fn run_degraded_worker(
Err(runtime_unavailable_issue(&shared)),
);
}
- AppSdkWorkerCommand::EnqueueOrderFulfillmentUpdate(_, response_sender) => {
- send_worker_result(
- &shared,
- response_sender,
- Err(runtime_unavailable_issue(&shared)),
- );
- }
- AppSdkWorkerCommand::EnqueueOrderReceiptRecord(_, response_sender) => {
- send_worker_result(
- &shared,
- response_sender,
- Err(runtime_unavailable_issue(&shared)),
- );
- }
AppSdkWorkerCommand::BeginProjectionRebuild(response_sender) => {
send_worker_result(
&shared,
@@ -1534,7 +1435,7 @@ fn enqueue_order_submit_with_sdk(
let receipt = runtime
.block_on(sdk.orders().enqueue_submit(enqueue, &signer))
.map_err(|error| AppSdkRuntimeIssue::from_sdk_error(&error))?;
- Ok(app_sdk_order_receipt(receipt, request.actor_pubkey))
+ Ok(app_sdk_order_submit_ack(receipt, request.actor_pubkey))
}
fn enqueue_order_decision_with_sdk(
@@ -1679,74 +1580,6 @@ fn enqueue_order_cancellation_with_sdk(
))
}
-fn enqueue_order_fulfillment_update_with_sdk(
- runtime: &tokio::runtime::Runtime,
- sdk: &RadrootsSdk,
- request: AppSdkOrderFulfillmentUpdateRequest,
-) -> Result<AppSdkWorkflowReceipt, AppSdkRuntimeIssue> {
- let actor = sdk_actor_context(
- request.actor_pubkey.as_str(),
- request.actor_account_id.as_str(),
- RadrootsActorRole::Seller,
- )?;
- let signer = sdk_local_signer(request.signer_keys)?;
- let target_relays = sdk_relay_targets(request.target_relays, request.relay_url_policy)?;
- ingest_order_evidence_with_sdk(runtime, sdk, request.evidence_events)?;
- let mut enqueue = OrderFulfillmentUpdateEnqueueRequest::new(
- actor,
- request.root_event,
- request.previous_event,
- request.fulfillment,
- target_relays,
- );
- if let Some(idempotency_key) = request.idempotency_key.as_deref() {
- enqueue = enqueue
- .try_with_idempotency_key(idempotency_key)
- .map_err(|error| AppSdkRuntimeIssue::from_sdk_error(&error))?;
- }
- let receipt = runtime
- .block_on(sdk.orders().enqueue_fulfillment_update(enqueue, &signer))
- .map_err(|error| AppSdkRuntimeIssue::from_sdk_error(&error))?;
- Ok(app_sdk_order_fulfillment_update_receipt(
- receipt,
- request.actor_pubkey,
- ))
-}
-
-fn enqueue_order_receipt_record_with_sdk(
- runtime: &tokio::runtime::Runtime,
- sdk: &RadrootsSdk,
- request: AppSdkOrderReceiptRecordRequest,
-) -> Result<AppSdkWorkflowReceipt, AppSdkRuntimeIssue> {
- let actor = sdk_actor_context(
- request.actor_pubkey.as_str(),
- request.actor_account_id.as_str(),
- RadrootsActorRole::Buyer,
- )?;
- let signer = sdk_local_signer(request.signer_keys)?;
- let target_relays = sdk_relay_targets(request.target_relays, request.relay_url_policy)?;
- ingest_order_evidence_with_sdk(runtime, sdk, request.evidence_events)?;
- let mut enqueue = OrderReceiptRecordEnqueueRequest::new(
- actor,
- request.root_event,
- request.previous_event,
- request.receipt,
- target_relays,
- );
- if let Some(idempotency_key) = request.idempotency_key.as_deref() {
- enqueue = enqueue
- .try_with_idempotency_key(idempotency_key)
- .map_err(|error| AppSdkRuntimeIssue::from_sdk_error(&error))?;
- }
- let receipt = runtime
- .block_on(sdk.orders().enqueue_receipt_record(enqueue, &signer))
- .map_err(|error| AppSdkRuntimeIssue::from_sdk_error(&error))?;
- Ok(app_sdk_order_receipt_record_receipt(
- receipt,
- request.actor_pubkey,
- ))
-}
-
fn ingest_order_evidence_with_sdk(
runtime: &tokio::runtime::Runtime,
sdk: &RadrootsSdk,
@@ -1821,7 +1654,7 @@ fn app_sdk_listing_receipt(
}
}
-fn app_sdk_order_receipt(
+fn app_sdk_order_submit_ack(
receipt: OrderSubmitReceipt,
actor_pubkey: String,
) -> AppSdkWorkflowReceipt {
@@ -1901,38 +1734,6 @@ fn app_sdk_order_cancellation_receipt(
}
}
-fn app_sdk_order_fulfillment_update_receipt(
- receipt: OrderFulfillmentUpdateReceipt,
- actor_pubkey: String,
-) -> AppSdkWorkflowReceipt {
- AppSdkWorkflowReceipt {
- operation_kind: ORDER_FULFILLMENT_UPDATE_OPERATION_KIND.to_owned(),
- expected_event_id: receipt.expected_event_id.as_str().to_owned(),
- signed_event_id: receipt.signed_event_id.as_str().to_owned(),
- outbox_operation_id: receipt.outbox_operation_id,
- outbox_event_id: receipt.outbox_event_id,
- state: sdk_mutation_state_key(receipt.state).to_owned(),
- idempotency_digest_prefix: receipt.idempotency_digest_prefix,
- actor_pubkey,
- }
-}
-
-fn app_sdk_order_receipt_record_receipt(
- receipt: OrderReceiptRecordReceipt,
- actor_pubkey: String,
-) -> AppSdkWorkflowReceipt {
- AppSdkWorkflowReceipt {
- operation_kind: ORDER_RECEIPT_RECORD_OPERATION_KIND.to_owned(),
- expected_event_id: receipt.expected_event_id.as_str().to_owned(),
- signed_event_id: receipt.signed_event_id.as_str().to_owned(),
- outbox_operation_id: receipt.outbox_operation_id,
- outbox_event_id: receipt.outbox_event_id,
- state: sdk_mutation_state_key(receipt.state).to_owned(),
- idempotency_digest_prefix: receipt.idempotency_digest_prefix,
- actor_pubkey,
- }
-}
-
fn sdk_mutation_state_key(state: SdkMutationState) -> &'static str {
match state {
SdkMutationState::StoredAndQueued => "enqueued",
diff --git a/crates/state/src/lib.rs b/crates/state/src/lib.rs
@@ -2273,8 +2273,7 @@ mod tests {
ProductsSort, ReminderDeliveryState, ReminderFeedProjection, ReminderKind,
ReminderLogEntryProjection, ReminderLogProjection, SelectedAccountProjection,
SelectedSurfaceProjection, SettingsSection, ShellSection, TodayAgendaProjection,
- TodaySetupTask, TodaySetupTaskKind, TradeEconomicsProjection, TradePaymentDisplayStatus,
- TradeWorkflowProjection,
+ TodaySetupTask, TodaySetupTaskKind, TradeEconomicsProjection, TradeWorkflowProjection,
};
struct FailingRepository;
@@ -2506,7 +2505,6 @@ mod tests {
currency_code: Some("USD".to_owned()),
..TradeEconomicsProjection::default()
};
- let order_payment = TradePaymentDisplayStatus::NotRecorded;
let orders_list = OrdersListProjection {
summary: OrdersListSummary {
total_orders: 2,
@@ -2528,7 +2526,6 @@ mod tests {
OrderStatus::NeedsAction,
),
primary_action: Some(OrderPrimaryAction::Review),
- fulfillment_actions: Vec::new(),
}],
};
let order_detail = OrderDetailProjection {
@@ -2551,15 +2548,13 @@ mod tests {
line_total_minor_units: Some(1300),
}],
economics: order_economics.clone(),
- payment: order_payment,
workflow: TradeWorkflowProjection::from_order_status(
order_id,
OrderStatus::NeedsAction,
)
- .with_economics_and_payment(order_economics, order_payment),
+ .with_economics(order_economics),
validation_receipts: Vec::new(),
primary_action: Some(OrderPrimaryAction::Review),
- fulfillment_actions: Vec::new(),
recoveries: Vec::new(),
};
let orders_reminders = ReminderFeedProjection {
diff --git a/crates/store/migrations/0001_init.sql b/crates/store/migrations/0001_init.sql
@@ -32,7 +32,7 @@ CREATE TABLE orders (
order_number TEXT NOT NULL,
customer_display_name TEXT NOT NULL,
status TEXT NOT NULL CHECK (
- status IN ('needs_action', 'scheduled', 'packed', 'completed', 'refunded')
+ status IN ('needs_action', 'scheduled', 'packed', 'completed')
),
updated_at TEXT NOT NULL
);
diff --git a/crates/store/migrations/0011_reminders_and_recovery.sql b/crates/store/migrations/0011_reminders_and_recovery.sql
@@ -9,7 +9,6 @@ CREATE TABLE reminder_schedules (
'fulfillment_window',
'order_action',
'missed_pickup_recovery',
- 'refund_recovery',
'sync_impact'
)
),
@@ -39,7 +38,6 @@ CREATE TABLE reminder_log_entries (
'fulfillment_window',
'order_action',
'missed_pickup_recovery',
- 'refund_recovery',
'sync_impact'
)
),
@@ -57,7 +55,7 @@ CREATE TABLE order_recovery_records (
farm_id TEXT NOT NULL,
order_id TEXT NOT NULL,
recovery_kind TEXT NOT NULL CHECK (
- recovery_kind IN ('missed_pickup', 'refund_follow_up')
+ recovery_kind IN ('missed_pickup')
),
recovery_state TEXT NOT NULL CHECK (
recovery_state IN ('open', 'in_review', 'resolved')
diff --git a/crates/store/migrations/0020_declined_order_status.sql b/crates/store/migrations/0020_declined_order_status.sql
@@ -16,7 +16,7 @@ CREATE TABLE orders (
order_number TEXT NOT NULL,
customer_display_name TEXT NOT NULL,
status TEXT NOT NULL CHECK (
- status IN ('needs_action', 'scheduled', 'packed', 'completed', 'declined', 'refunded')
+ status IN ('needs_action', 'scheduled', 'packed', 'completed', 'declined')
),
updated_at TEXT NOT NULL,
buyer_context_key TEXT,
diff --git a/crates/store/migrations/0023_order_workflow_display_projection.sql b/crates/store/migrations/0023_order_workflow_display_projection.sql
@@ -1,11 +1,6 @@
ALTER TABLE orders
ADD COLUMN workflow_agreement TEXT NOT NULL DEFAULT 'ordered' CHECK (
- workflow_agreement IN ('ordered', 'confirmed', 'declined', 'cancelled', 'completed', 'needs_review')
- );
-
-ALTER TABLE orders
- ADD COLUMN workflow_fulfillment TEXT CHECK (
- workflow_fulfillment IS NULL OR workflow_fulfillment IN ('confirmed', 'preparing', 'ready_for_pickup', 'out_for_delivery', 'delivered', 'cancelled')
+ workflow_agreement IN ('ordered', 'confirmed', 'declined', 'cancelled', 'needs_review')
);
ALTER TABLE orders
@@ -14,11 +9,6 @@ ALTER TABLE orders
);
ALTER TABLE orders
- ADD COLUMN workflow_payment TEXT NOT NULL DEFAULT 'not_recorded' CHECK (
- workflow_payment IN ('not_recorded', 'recorded', 'needs_review')
- );
-
-ALTER TABLE orders
ADD COLUMN workflow_provenance_source TEXT NOT NULL DEFAULT 'unknown' CHECK (
workflow_provenance_source IN ('app', 'cli', 'relay', 'local_events', 'unknown')
);
@@ -31,26 +21,14 @@ SET
workflow_agreement = CASE status
WHEN 'scheduled' THEN 'confirmed'
WHEN 'packed' THEN 'confirmed'
- WHEN 'completed' THEN 'completed'
+ WHEN 'completed' THEN 'confirmed'
WHEN 'declined' THEN 'declined'
- WHEN 'refunded' THEN 'needs_review'
ELSE 'ordered'
END,
- workflow_fulfillment = CASE status
- WHEN 'scheduled' THEN 'confirmed'
- WHEN 'packed' THEN 'ready_for_pickup'
- WHEN 'completed' THEN 'delivered'
- WHEN 'declined' THEN 'cancelled'
- ELSE NULL
- END,
workflow_inventory = CASE status
WHEN 'scheduled' THEN 'reserved'
WHEN 'packed' THEN 'reserved'
WHEN 'completed' THEN 'reserved'
WHEN 'declined' THEN 'available'
ELSE 'needs_review'
- END,
- workflow_payment = CASE status
- WHEN 'refunded' THEN 'needs_review'
- ELSE 'not_recorded'
END;
diff --git a/crates/store/migrations/0024_order_workflow_agreement_states.sql b/crates/store/migrations/0024_order_workflow_agreement_states.sql
@@ -0,0 +1 @@
+SELECT 1;
diff --git a/crates/store/migrations/0024_order_workflow_payment_display_states.sql b/crates/store/migrations/0024_order_workflow_payment_display_states.sql
@@ -1,196 +0,0 @@
-DROP INDEX IF EXISTS idx_order_lines_order_sort;
-DROP INDEX IF EXISTS idx_buyer_order_coordination_context_state_updated_at;
-DROP INDEX IF EXISTS idx_buyer_order_coordination_state_updated_at;
-DROP INDEX IF EXISTS idx_orders_farm_status;
-DROP INDEX IF EXISTS idx_orders_farm_window_status_updated_at;
-DROP INDEX IF EXISTS idx_orders_buyer_context_updated_at;
-
-ALTER TABLE order_lines RENAME TO order_lines_payment_display_legacy;
-ALTER TABLE buyer_order_coordination_records RENAME TO buyer_order_coordination_records_payment_display_legacy;
-ALTER TABLE orders RENAME TO orders_payment_display_legacy;
-
-CREATE TABLE orders (
- id TEXT PRIMARY KEY NOT NULL,
- farm_id TEXT NOT NULL REFERENCES farms(id) ON DELETE CASCADE,
- fulfillment_window_id TEXT REFERENCES fulfillment_windows(id) ON DELETE SET NULL,
- order_number TEXT NOT NULL,
- customer_display_name TEXT NOT NULL,
- status TEXT NOT NULL CHECK (
- status IN ('needs_action', 'scheduled', 'packed', 'completed', 'declined', 'refunded')
- ),
- updated_at TEXT NOT NULL,
- buyer_context_key TEXT,
- buyer_email TEXT NOT NULL DEFAULT '',
- buyer_phone TEXT NOT NULL DEFAULT '',
- buyer_order_note TEXT NOT NULL DEFAULT '',
- workflow_revision TEXT NOT NULL DEFAULT 'none' CHECK (
- workflow_revision IN ('none', 'change_proposed', 'updated', 'kept_as_placed')
- ),
- workflow_agreement TEXT NOT NULL DEFAULT 'ordered' CHECK (
- workflow_agreement IN ('ordered', 'confirmed', 'declined', 'cancelled', 'completed', 'needs_review')
- ),
- workflow_fulfillment TEXT CHECK (
- workflow_fulfillment IS NULL OR workflow_fulfillment IN ('confirmed', 'preparing', 'ready_for_pickup', 'out_for_delivery', 'delivered', 'cancelled')
- ),
- workflow_inventory TEXT NOT NULL DEFAULT 'needs_review' CHECK (
- workflow_inventory IN ('available', 'reserved', 'sold_out', 'needs_review')
- ),
- workflow_payment TEXT NOT NULL DEFAULT 'not_recorded' CHECK (
- workflow_payment IN ('not_recorded', 'pending', 'recorded', 'settled', 'needs_review')
- ),
- workflow_provenance_source TEXT NOT NULL DEFAULT 'unknown' CHECK (
- workflow_provenance_source IN ('app', 'cli', 'relay', 'local_events', 'unknown')
- ),
- workflow_provenance_last_event_id TEXT
-);
-
-INSERT INTO orders (
- id,
- farm_id,
- fulfillment_window_id,
- order_number,
- customer_display_name,
- status,
- updated_at,
- buyer_context_key,
- buyer_email,
- buyer_phone,
- buyer_order_note,
- workflow_revision,
- workflow_agreement,
- workflow_fulfillment,
- workflow_inventory,
- workflow_payment,
- workflow_provenance_source,
- workflow_provenance_last_event_id
-)
-SELECT
- id,
- farm_id,
- fulfillment_window_id,
- order_number,
- customer_display_name,
- status,
- updated_at,
- buyer_context_key,
- buyer_email,
- buyer_phone,
- buyer_order_note,
- workflow_revision,
- workflow_agreement,
- workflow_fulfillment,
- workflow_inventory,
- workflow_payment,
- workflow_provenance_source,
- workflow_provenance_last_event_id
-FROM orders_payment_display_legacy;
-
-CREATE TABLE order_lines (
- id TEXT PRIMARY KEY NOT NULL,
- order_id TEXT NOT NULL REFERENCES orders(id) ON DELETE CASCADE,
- title TEXT NOT NULL,
- quantity_value INTEGER NOT NULL CHECK (quantity_value >= 0),
- quantity_unit_label TEXT NOT NULL DEFAULT '',
- quantity_display TEXT NOT NULL,
- sort_index INTEGER NOT NULL DEFAULT 0,
- listing_bin_id TEXT,
- unit_price_minor_units INTEGER CHECK (
- unit_price_minor_units IS NULL OR unit_price_minor_units >= 0
- ),
- price_currency TEXT NOT NULL DEFAULT 'USD',
- farm_key TEXT,
- listing_addr TEXT,
- listing_event_id TEXT,
- seller_pubkey TEXT,
- listing_relays_json TEXT
-);
-
-INSERT INTO order_lines (
- id,
- order_id,
- title,
- quantity_value,
- quantity_unit_label,
- quantity_display,
- sort_index,
- listing_bin_id,
- unit_price_minor_units,
- price_currency,
- farm_key,
- listing_addr,
- listing_event_id,
- seller_pubkey,
- listing_relays_json
-)
-SELECT
- id,
- order_id,
- title,
- quantity_value,
- quantity_unit_label,
- quantity_display,
- sort_index,
- listing_bin_id,
- unit_price_minor_units,
- price_currency,
- farm_key,
- listing_addr,
- listing_event_id,
- seller_pubkey,
- listing_relays_json
-FROM order_lines_payment_display_legacy;
-
-CREATE TABLE buyer_order_coordination_records (
- order_id TEXT PRIMARY KEY NOT NULL REFERENCES orders(id) ON DELETE CASCADE,
- buyer_context_key TEXT NOT NULL,
- record_id TEXT,
- state TEXT NOT NULL CHECK (state IN ('pending', 'synced', 'failed')),
- payload_json TEXT,
- attempt_count INTEGER NOT NULL DEFAULT 0 CHECK (attempt_count >= 0),
- last_error_message TEXT,
- created_at TEXT NOT NULL,
- updated_at TEXT NOT NULL,
- synced_at TEXT
-);
-
-INSERT INTO buyer_order_coordination_records (
- order_id,
- buyer_context_key,
- record_id,
- state,
- payload_json,
- attempt_count,
- last_error_message,
- created_at,
- updated_at,
- synced_at
-)
-SELECT
- order_id,
- buyer_context_key,
- record_id,
- state,
- payload_json,
- attempt_count,
- last_error_message,
- created_at,
- updated_at,
- synced_at
-FROM buyer_order_coordination_records_payment_display_legacy;
-
-CREATE INDEX idx_orders_farm_status ON orders(farm_id, status);
-CREATE INDEX idx_orders_farm_window_status_updated_at
- ON orders(farm_id, fulfillment_window_id, status, updated_at DESC, id DESC);
-CREATE INDEX idx_orders_buyer_context_updated_at
- ON orders(buyer_context_key, updated_at DESC, id DESC)
- WHERE buyer_context_key IS NOT NULL AND trim(buyer_context_key) <> '';
-CREATE INDEX idx_order_lines_order_sort
- ON order_lines(order_id, sort_index, id);
-CREATE INDEX idx_buyer_order_coordination_context_state_updated_at
- ON buyer_order_coordination_records(buyer_context_key, state, updated_at);
-CREATE INDEX idx_buyer_order_coordination_state_updated_at
- ON buyer_order_coordination_records(state, updated_at);
-
-DROP TABLE order_lines_payment_display_legacy;
-DROP TABLE buyer_order_coordination_records_payment_display_legacy;
-DROP TABLE orders_payment_display_legacy;
diff --git a/crates/store/migrations/0025_order_receipt_display_projection.sql b/crates/store/migrations/0025_order_receipt_display_projection.sql
@@ -1,204 +0,0 @@
-DROP INDEX IF EXISTS idx_order_lines_order_sort;
-DROP INDEX IF EXISTS idx_buyer_order_coordination_context_state_updated_at;
-DROP INDEX IF EXISTS idx_buyer_order_coordination_state_updated_at;
-DROP INDEX IF EXISTS idx_orders_farm_status;
-DROP INDEX IF EXISTS idx_orders_farm_window_status_updated_at;
-DROP INDEX IF EXISTS idx_orders_buyer_context_updated_at;
-
-ALTER TABLE order_lines RENAME TO order_lines_receipt_display_legacy;
-ALTER TABLE buyer_order_coordination_records RENAME TO buyer_order_coordination_records_receipt_display_legacy;
-ALTER TABLE orders RENAME TO orders_receipt_display_legacy;
-
-CREATE TABLE orders (
- id TEXT PRIMARY KEY NOT NULL,
- farm_id TEXT NOT NULL REFERENCES farms(id) ON DELETE CASCADE,
- fulfillment_window_id TEXT REFERENCES fulfillment_windows(id) ON DELETE SET NULL,
- order_number TEXT NOT NULL,
- customer_display_name TEXT NOT NULL,
- status TEXT NOT NULL CHECK (
- status IN ('needs_action', 'scheduled', 'packed', 'completed', 'declined', 'refunded', 'needs_review')
- ),
- updated_at TEXT NOT NULL,
- buyer_context_key TEXT,
- buyer_email TEXT NOT NULL DEFAULT '',
- buyer_phone TEXT NOT NULL DEFAULT '',
- buyer_order_note TEXT NOT NULL DEFAULT '',
- workflow_revision TEXT NOT NULL DEFAULT 'none' CHECK (
- workflow_revision IN ('none', 'change_proposed', 'updated', 'kept_as_placed')
- ),
- workflow_agreement TEXT NOT NULL DEFAULT 'ordered' CHECK (
- workflow_agreement IN ('ordered', 'confirmed', 'declined', 'cancelled', 'completed', 'needs_review')
- ),
- workflow_fulfillment TEXT CHECK (
- workflow_fulfillment IS NULL OR workflow_fulfillment IN ('confirmed', 'preparing', 'ready_for_pickup', 'out_for_delivery', 'delivered', 'cancelled')
- ),
- workflow_receipt_event_id TEXT,
- workflow_receipt_received INTEGER CHECK (
- workflow_receipt_received IS NULL OR workflow_receipt_received IN (0, 1)
- ),
- workflow_receipt_issue TEXT,
- workflow_receipt_received_at INTEGER CHECK (
- workflow_receipt_received_at IS NULL OR workflow_receipt_received_at >= 0
- ),
- workflow_inventory TEXT NOT NULL DEFAULT 'needs_review' CHECK (
- workflow_inventory IN ('available', 'reserved', 'sold_out', 'needs_review')
- ),
- workflow_payment TEXT NOT NULL DEFAULT 'not_recorded' CHECK (
- workflow_payment IN ('not_recorded', 'pending', 'recorded', 'settled', 'needs_review')
- ),
- workflow_provenance_source TEXT NOT NULL DEFAULT 'unknown' CHECK (
- workflow_provenance_source IN ('app', 'cli', 'relay', 'local_events', 'unknown')
- ),
- workflow_provenance_last_event_id TEXT
-);
-
-INSERT INTO orders (
- id,
- farm_id,
- fulfillment_window_id,
- order_number,
- customer_display_name,
- status,
- updated_at,
- buyer_context_key,
- buyer_email,
- buyer_phone,
- buyer_order_note,
- workflow_revision,
- workflow_agreement,
- workflow_fulfillment,
- workflow_inventory,
- workflow_payment,
- workflow_provenance_source,
- workflow_provenance_last_event_id
-)
-SELECT
- id,
- farm_id,
- fulfillment_window_id,
- order_number,
- customer_display_name,
- status,
- updated_at,
- buyer_context_key,
- buyer_email,
- buyer_phone,
- buyer_order_note,
- workflow_revision,
- workflow_agreement,
- workflow_fulfillment,
- workflow_inventory,
- workflow_payment,
- workflow_provenance_source,
- workflow_provenance_last_event_id
-FROM orders_receipt_display_legacy;
-
-CREATE TABLE order_lines (
- id TEXT PRIMARY KEY NOT NULL,
- order_id TEXT NOT NULL REFERENCES orders(id) ON DELETE CASCADE,
- title TEXT NOT NULL,
- quantity_value INTEGER NOT NULL CHECK (quantity_value >= 0),
- quantity_unit_label TEXT NOT NULL DEFAULT '',
- quantity_display TEXT NOT NULL,
- sort_index INTEGER NOT NULL DEFAULT 0,
- listing_bin_id TEXT,
- unit_price_minor_units INTEGER CHECK (
- unit_price_minor_units IS NULL OR unit_price_minor_units >= 0
- ),
- price_currency TEXT NOT NULL DEFAULT 'USD',
- farm_key TEXT,
- listing_addr TEXT,
- listing_event_id TEXT,
- seller_pubkey TEXT,
- listing_relays_json TEXT
-);
-
-INSERT INTO order_lines (
- id,
- order_id,
- title,
- quantity_value,
- quantity_unit_label,
- quantity_display,
- sort_index,
- listing_bin_id,
- unit_price_minor_units,
- price_currency,
- farm_key,
- listing_addr,
- listing_event_id,
- seller_pubkey,
- listing_relays_json
-)
-SELECT
- id,
- order_id,
- title,
- quantity_value,
- quantity_unit_label,
- quantity_display,
- sort_index,
- listing_bin_id,
- unit_price_minor_units,
- price_currency,
- farm_key,
- listing_addr,
- listing_event_id,
- seller_pubkey,
- listing_relays_json
-FROM order_lines_receipt_display_legacy;
-
-CREATE TABLE buyer_order_coordination_records (
- order_id TEXT PRIMARY KEY NOT NULL REFERENCES orders(id) ON DELETE CASCADE,
- buyer_context_key TEXT NOT NULL,
- record_id TEXT,
- state TEXT NOT NULL CHECK (state IN ('pending', 'synced', 'failed')),
- payload_json TEXT,
- attempt_count INTEGER NOT NULL DEFAULT 0 CHECK (attempt_count >= 0),
- last_error_message TEXT,
- created_at TEXT NOT NULL,
- updated_at TEXT NOT NULL,
- synced_at TEXT
-);
-
-INSERT INTO buyer_order_coordination_records (
- order_id,
- buyer_context_key,
- record_id,
- state,
- payload_json,
- attempt_count,
- last_error_message,
- created_at,
- updated_at,
- synced_at
-)
-SELECT
- order_id,
- buyer_context_key,
- record_id,
- state,
- payload_json,
- attempt_count,
- last_error_message,
- created_at,
- updated_at,
- synced_at
-FROM buyer_order_coordination_records_receipt_display_legacy;
-
-CREATE INDEX idx_orders_farm_status ON orders(farm_id, status);
-CREATE INDEX idx_orders_farm_window_status_updated_at
- ON orders(farm_id, fulfillment_window_id, status, updated_at DESC, id DESC);
-CREATE INDEX idx_orders_buyer_context_updated_at
- ON orders(buyer_context_key, updated_at DESC, id DESC)
- WHERE buyer_context_key IS NOT NULL AND trim(buyer_context_key) <> '';
-CREATE INDEX idx_order_lines_order_sort
- ON order_lines(order_id, sort_index, id);
-CREATE INDEX idx_buyer_order_coordination_context_state_updated_at
- ON buyer_order_coordination_records(buyer_context_key, state, updated_at);
-CREATE INDEX idx_buyer_order_coordination_state_updated_at
- ON buyer_order_coordination_records(state, updated_at);
-
-DROP TABLE order_lines_receipt_display_legacy;
-DROP TABLE buyer_order_coordination_records_receipt_display_legacy;
-DROP TABLE orders_receipt_display_legacy;
diff --git a/crates/store/migrations/0025_order_workflow_agreement_projection.sql b/crates/store/migrations/0025_order_workflow_agreement_projection.sql
@@ -0,0 +1,186 @@
+DROP INDEX IF EXISTS idx_order_lines_order_sort;
+DROP INDEX IF EXISTS idx_buyer_order_coordination_context_state_updated_at;
+DROP INDEX IF EXISTS idx_buyer_order_coordination_state_updated_at;
+DROP INDEX IF EXISTS idx_orders_farm_status;
+DROP INDEX IF EXISTS idx_orders_farm_window_status_updated_at;
+DROP INDEX IF EXISTS idx_orders_buyer_context_updated_at;
+
+ALTER TABLE order_lines RENAME TO order_lines_agreement_legacy;
+ALTER TABLE buyer_order_coordination_records RENAME TO buyer_order_coordination_records_agreement_legacy;
+ALTER TABLE orders RENAME TO orders_agreement_legacy;
+
+CREATE TABLE orders (
+ id TEXT PRIMARY KEY NOT NULL,
+ farm_id TEXT NOT NULL REFERENCES farms(id) ON DELETE CASCADE,
+ fulfillment_window_id TEXT REFERENCES fulfillment_windows(id) ON DELETE SET NULL,
+ order_number TEXT NOT NULL,
+ customer_display_name TEXT NOT NULL,
+ status TEXT NOT NULL CHECK (
+ status IN ('needs_action', 'scheduled', 'packed', 'completed', 'declined', 'needs_review')
+ ),
+ updated_at TEXT NOT NULL,
+ buyer_context_key TEXT,
+ buyer_email TEXT NOT NULL DEFAULT '',
+ buyer_phone TEXT NOT NULL DEFAULT '',
+ buyer_order_note TEXT NOT NULL DEFAULT '',
+ workflow_revision TEXT NOT NULL DEFAULT 'none' CHECK (
+ workflow_revision IN ('none', 'change_proposed', 'updated', 'kept_as_placed')
+ ),
+ workflow_agreement TEXT NOT NULL DEFAULT 'ordered' CHECK (
+ workflow_agreement IN ('ordered', 'confirmed', 'declined', 'cancelled', 'needs_review')
+ ),
+ workflow_inventory TEXT NOT NULL DEFAULT 'needs_review' CHECK (
+ workflow_inventory IN ('available', 'reserved', 'sold_out', 'needs_review')
+ ),
+ workflow_provenance_source TEXT NOT NULL DEFAULT 'unknown' CHECK (
+ workflow_provenance_source IN ('app', 'cli', 'relay', 'local_events', 'unknown')
+ ),
+ workflow_provenance_last_event_id TEXT
+);
+
+INSERT INTO orders (
+ id,
+ farm_id,
+ fulfillment_window_id,
+ order_number,
+ customer_display_name,
+ status,
+ updated_at,
+ buyer_context_key,
+ buyer_email,
+ buyer_phone,
+ buyer_order_note,
+ workflow_revision,
+ workflow_agreement,
+ workflow_inventory,
+ workflow_provenance_source,
+ workflow_provenance_last_event_id
+)
+SELECT
+ id,
+ farm_id,
+ fulfillment_window_id,
+ order_number,
+ customer_display_name,
+ status,
+ updated_at,
+ buyer_context_key,
+ buyer_email,
+ buyer_phone,
+ buyer_order_note,
+ workflow_revision,
+ workflow_agreement,
+ workflow_inventory,
+ workflow_provenance_source,
+ workflow_provenance_last_event_id
+FROM orders_agreement_legacy;
+
+CREATE TABLE order_lines (
+ id TEXT PRIMARY KEY NOT NULL,
+ order_id TEXT NOT NULL REFERENCES orders(id) ON DELETE CASCADE,
+ title TEXT NOT NULL,
+ quantity_value INTEGER NOT NULL CHECK (quantity_value >= 0),
+ quantity_unit_label TEXT NOT NULL DEFAULT '',
+ quantity_display TEXT NOT NULL,
+ sort_index INTEGER NOT NULL DEFAULT 0,
+ listing_bin_id TEXT,
+ unit_price_minor_units INTEGER CHECK (
+ unit_price_minor_units IS NULL OR unit_price_minor_units >= 0
+ ),
+ price_currency TEXT NOT NULL DEFAULT 'USD',
+ farm_key TEXT,
+ listing_addr TEXT,
+ listing_event_id TEXT,
+ seller_pubkey TEXT,
+ listing_relays_json TEXT
+);
+
+INSERT INTO order_lines (
+ id,
+ order_id,
+ title,
+ quantity_value,
+ quantity_unit_label,
+ quantity_display,
+ sort_index,
+ listing_bin_id,
+ unit_price_minor_units,
+ price_currency,
+ farm_key,
+ listing_addr,
+ listing_event_id,
+ seller_pubkey,
+ listing_relays_json
+)
+SELECT
+ id,
+ order_id,
+ title,
+ quantity_value,
+ quantity_unit_label,
+ quantity_display,
+ sort_index,
+ listing_bin_id,
+ unit_price_minor_units,
+ price_currency,
+ farm_key,
+ listing_addr,
+ listing_event_id,
+ seller_pubkey,
+ listing_relays_json
+FROM order_lines_agreement_legacy;
+
+CREATE TABLE buyer_order_coordination_records (
+ order_id TEXT PRIMARY KEY NOT NULL REFERENCES orders(id) ON DELETE CASCADE,
+ buyer_context_key TEXT NOT NULL,
+ record_id TEXT,
+ state TEXT NOT NULL CHECK (state IN ('pending', 'synced', 'failed')),
+ payload_json TEXT,
+ attempt_count INTEGER NOT NULL DEFAULT 0 CHECK (attempt_count >= 0),
+ last_error_message TEXT,
+ created_at TEXT NOT NULL,
+ updated_at TEXT NOT NULL,
+ synced_at TEXT
+);
+
+INSERT INTO buyer_order_coordination_records (
+ order_id,
+ buyer_context_key,
+ record_id,
+ state,
+ payload_json,
+ attempt_count,
+ last_error_message,
+ created_at,
+ updated_at,
+ synced_at
+)
+SELECT
+ order_id,
+ buyer_context_key,
+ record_id,
+ state,
+ payload_json,
+ attempt_count,
+ last_error_message,
+ created_at,
+ updated_at,
+ synced_at
+FROM buyer_order_coordination_records_agreement_legacy;
+
+CREATE INDEX idx_orders_farm_status ON orders(farm_id, status);
+CREATE INDEX idx_orders_farm_window_status_updated_at
+ ON orders(farm_id, fulfillment_window_id, status, updated_at DESC, id DESC);
+CREATE INDEX idx_orders_buyer_context_updated_at
+ ON orders(buyer_context_key, updated_at DESC, id DESC)
+ WHERE buyer_context_key IS NOT NULL AND trim(buyer_context_key) <> '';
+CREATE INDEX idx_order_lines_order_sort
+ ON order_lines(order_id, sort_index, id);
+CREATE INDEX idx_buyer_order_coordination_context_state_updated_at
+ ON buyer_order_coordination_records(buyer_context_key, state, updated_at);
+CREATE INDEX idx_buyer_order_coordination_state_updated_at
+ ON buyer_order_coordination_records(state, updated_at);
+
+DROP TABLE order_lines_agreement_legacy;
+DROP TABLE buyer_order_coordination_records_agreement_legacy;
+DROP TABLE orders_agreement_legacy;
diff --git a/crates/store/src/interop.rs b/crates/store/src/interop.rs
@@ -15,13 +15,9 @@ use radroots_events::{
KIND_LISTING_DRAFT as RADROOTS_KIND_LISTING_DRAFT,
KIND_ORDER_CANCELLATION as RADROOTS_KIND_ORDER_CANCELLATION,
KIND_ORDER_DECISION as RADROOTS_KIND_ORDER_DECISION,
- KIND_ORDER_FULFILLMENT_UPDATE as RADROOTS_KIND_ORDER_FULFILLMENT_UPDATE,
- KIND_ORDER_PAYMENT_RECORD as RADROOTS_KIND_ORDER_PAYMENT_RECORD,
- KIND_ORDER_RECEIPT as RADROOTS_KIND_ORDER_RECEIPT,
KIND_ORDER_REQUEST as RADROOTS_KIND_ORDER_REQUEST,
KIND_ORDER_REVISION_DECISION as RADROOTS_KIND_ORDER_REVISION_DECISION,
KIND_ORDER_REVISION_PROPOSAL as RADROOTS_KIND_ORDER_REVISION_PROPOSAL,
- KIND_ORDER_SETTLEMENT_DECISION as RADROOTS_KIND_ORDER_SETTLEMENT_DECISION,
KIND_TRADE_VALIDATION_RECEIPT,
},
order::{
@@ -31,9 +27,8 @@ use radroots_events::{
};
use radroots_events_codec::order::{
order_cancellation_from_event, order_decision_from_event, order_event_context_from_tags,
- order_fulfillment_update_from_event, order_payment_record_from_event, order_receipt_from_event,
order_request_from_event, order_revision_decision_from_event,
- order_revision_proposal_from_event, order_settlement_decision_from_event,
+ order_revision_proposal_from_event,
};
use radroots_local_events::{
LocalEventRecord, LocalEventsStore, LocalRecordFamily, LocalRecordStatus, PublishOutboxStatus,
@@ -41,10 +36,9 @@ use radroots_local_events::{
};
use radroots_sql_core::{SqlExecutor, SqliteExecutor};
use radroots_trade::order::{
- RadrootsOrderCancellationRecord, RadrootsOrderDecisionRecord, RadrootsOrderFulfillmentRecord,
- RadrootsOrderPaymentEventRecord, RadrootsOrderProjection, RadrootsOrderReceiptRecord,
+ RadrootsOrderCancellationRecord, RadrootsOrderDecisionRecord, RadrootsOrderProjection,
RadrootsOrderReductionInputs, RadrootsOrderRequestRecord, RadrootsOrderRevisionDecisionRecord,
- RadrootsOrderRevisionProposalRecord, RadrootsOrderSettlementRecord, reduce_order_events,
+ RadrootsOrderRevisionProposalRecord, reduce_order_events,
};
use radroots_trade::validation_receipt::{
RadrootsTradeValidationReceipt, RadrootsValidationReceiptTags, validation_receipt_from_event,
@@ -66,21 +60,13 @@ const KIND_ORDER_DECISION: i64 = RADROOTS_KIND_ORDER_DECISION as i64;
const KIND_ORDER_REVISION: i64 = RADROOTS_KIND_ORDER_REVISION_PROPOSAL as i64;
const KIND_ORDER_REVISION_DECISION: i64 = RADROOTS_KIND_ORDER_REVISION_DECISION as i64;
const KIND_ORDER_CANCEL: i64 = RADROOTS_KIND_ORDER_CANCELLATION as i64;
-const KIND_ORDER_FULFILLMENT: i64 = RADROOTS_KIND_ORDER_FULFILLMENT_UPDATE as i64;
-const KIND_ORDER_RECEIPT: i64 = RADROOTS_KIND_ORDER_RECEIPT as i64;
-const KIND_ORDER_PAYMENT: i64 = RADROOTS_KIND_ORDER_PAYMENT_RECORD as i64;
-const KIND_ORDER_SETTLEMENT: i64 = RADROOTS_KIND_ORDER_SETTLEMENT_DECISION as i64;
const KIND_VALIDATION_RECEIPT: i64 = KIND_TRADE_VALIDATION_RECEIPT as i64;
-const ACTIVE_ORDER_EVENT_KINDS: [i64; 9] = [
+const ACTIVE_ORDER_EVENT_KINDS: [i64; 5] = [
KIND_ORDER_REQUEST,
KIND_ORDER_DECISION,
KIND_ORDER_REVISION,
KIND_ORDER_REVISION_DECISION,
KIND_ORDER_CANCEL,
- KIND_ORDER_FULFILLMENT,
- KIND_ORDER_RECEIPT,
- KIND_ORDER_PAYMENT,
- KIND_ORDER_SETTLEMENT,
];
#[derive(Clone, Debug, Default, Eq, PartialEq)]
@@ -1202,11 +1188,7 @@ impl<'a> AppLocalInteropRepository<'a> {
decisions: buckets.decisions,
revision_proposals: buckets.revision_proposals,
revision_decisions: buckets.revision_decisions,
- fulfillments: buckets.fulfillments,
cancellations: buckets.cancellations,
- receipts: buckets.receipts,
- payments: buckets.payments,
- settlements: buckets.settlements,
},
);
let request_payload = projection.request_event_id.as_deref().and_then(|event_id| {
@@ -1312,15 +1294,9 @@ impl<'a> AppLocalInteropRepository<'a> {
SET status = ?2,
workflow_revision = ?3,
workflow_agreement = ?4,
- workflow_fulfillment = ?5,
- workflow_receipt_event_id = ?6,
- workflow_receipt_received = ?7,
- workflow_receipt_issue = ?8,
- workflow_receipt_received_at = ?9,
- workflow_inventory = ?10,
- workflow_payment = ?11,
- workflow_provenance_source = ?12,
- workflow_provenance_last_event_id = ?13,
+ workflow_inventory = ?5,
+ workflow_provenance_source = ?6,
+ workflow_provenance_last_event_id = ?7,
updated_at = strftime('%Y-%m-%dT%H:%M:%SZ', 'now')
WHERE id = ?1",
params![
@@ -1328,31 +1304,7 @@ impl<'a> AppLocalInteropRepository<'a> {
status.storage_key(),
workflow.revision.storage_key(),
workflow.agreement.storage_key(),
- workflow
- .fulfillment
- .map(|fulfillment| fulfillment.storage_key()),
- workflow
- .receipt
- .as_ref()
- .map(|receipt| receipt.event_id.as_str()),
- workflow
- .receipt
- .as_ref()
- .map(|receipt| if receipt.received { 1_i64 } else { 0_i64 }),
- workflow
- .receipt
- .as_ref()
- .and_then(|receipt| receipt.issue.as_deref()),
- workflow
- .receipt
- .as_ref()
- .map(|receipt| i64::try_from(receipt.received_at))
- .transpose()
- .map_err(|_| AppSqliteError::InvalidProjection {
- reason: "receipt timestamp must fit sqlite integer",
- })?,
workflow.inventory.storage_key(),
- workflow.payment.storage_key(),
workflow.provenance.primary_source.storage_key(),
workflow.provenance.last_event_id.as_deref()
],
@@ -2729,11 +2681,7 @@ enum ActiveOrderEvidence {
Decision(RadrootsOrderDecisionRecord),
RevisionProposal(RadrootsOrderRevisionProposalRecord),
RevisionDecision(RadrootsOrderRevisionDecisionRecord),
- Fulfillment(RadrootsOrderFulfillmentRecord),
Cancellation(RadrootsOrderCancellationRecord),
- Receipt(RadrootsOrderReceiptRecord),
- Payment(RadrootsOrderPaymentEventRecord),
- Settlement(RadrootsOrderSettlementRecord),
}
impl ActiveOrderEvidence {
@@ -2743,11 +2691,7 @@ impl ActiveOrderEvidence {
Self::Decision(record) => record.event_id.as_str(),
Self::RevisionProposal(record) => record.event_id.as_str(),
Self::RevisionDecision(record) => record.event_id.as_str(),
- Self::Fulfillment(record) => record.event_id.as_str(),
Self::Cancellation(record) => record.event_id.as_str(),
- Self::Receipt(record) => record.event_id.as_str(),
- Self::Payment(record) => record.event_id.as_str(),
- Self::Settlement(record) => record.event_id.as_str(),
}
}
@@ -2757,11 +2701,7 @@ impl ActiveOrderEvidence {
Self::Decision(record) => record.payload.order_id.as_str(),
Self::RevisionProposal(record) => record.payload.order_id.as_str(),
Self::RevisionDecision(record) => record.payload.order_id.as_str(),
- Self::Fulfillment(record) => record.payload.order_id.as_str(),
Self::Cancellation(record) => record.payload.order_id.as_str(),
- Self::Receipt(record) => record.payload.order_id.as_str(),
- Self::Payment(record) => record.payload.order_id.as_str(),
- Self::Settlement(record) => record.payload.order_id.as_str(),
}
}
@@ -2783,26 +2723,10 @@ impl ActiveOrderEvidence {
record.payload.order_id.as_str(),
record.payload.buyer_pubkey.as_str(),
),
- Self::Fulfillment(record) => (
- record.payload.order_id.as_str(),
- record.payload.buyer_pubkey.as_str(),
- ),
Self::Cancellation(record) => (
record.payload.order_id.as_str(),
record.payload.buyer_pubkey.as_str(),
),
- Self::Receipt(record) => (
- record.payload.order_id.as_str(),
- record.payload.buyer_pubkey.as_str(),
- ),
- Self::Payment(record) => (
- record.payload.order_id.as_str(),
- record.payload.buyer_pubkey.as_str(),
- ),
- Self::Settlement(record) => (
- record.payload.order_id.as_str(),
- record.payload.buyer_pubkey.as_str(),
- ),
}
}
}
@@ -2813,11 +2737,7 @@ struct ActiveOrderEvidenceBuckets {
decisions: Vec<RadrootsOrderDecisionRecord>,
revision_proposals: Vec<RadrootsOrderRevisionProposalRecord>,
revision_decisions: Vec<RadrootsOrderRevisionDecisionRecord>,
- fulfillments: Vec<RadrootsOrderFulfillmentRecord>,
cancellations: Vec<RadrootsOrderCancellationRecord>,
- receipts: Vec<RadrootsOrderReceiptRecord>,
- payments: Vec<RadrootsOrderPaymentEventRecord>,
- settlements: Vec<RadrootsOrderSettlementRecord>,
}
impl ActiveOrderEvidenceBuckets {
@@ -2833,11 +2753,7 @@ impl ActiveOrderEvidenceBuckets {
ActiveOrderEvidence::RevisionDecision(record) => {
buckets.revision_decisions.push(record);
}
- ActiveOrderEvidence::Fulfillment(record) => buckets.fulfillments.push(record),
ActiveOrderEvidence::Cancellation(record) => buckets.cancellations.push(record),
- ActiveOrderEvidence::Receipt(record) => buckets.receipts.push(record),
- ActiveOrderEvidence::Payment(record) => buckets.payments.push(record),
- ActiveOrderEvidence::Settlement(record) => buckets.settlements.push(record),
}
}
buckets
@@ -3064,60 +2980,6 @@ fn active_order_evidence_from_event(event: &RadrootsNostrEvent) -> Option<Active
},
))
}
- KIND_ORDER_FULFILLMENT => {
- let envelope = order_fulfillment_update_from_event(event).ok()?;
- let context = order_event_context_from_tags(envelope.message_type, &event.tags).ok()?;
- Some(ActiveOrderEvidence::Fulfillment(
- RadrootsOrderFulfillmentRecord {
- event_id: active_event_id(event)?,
- author_pubkey: active_author_pubkey(event)?,
- counterparty_pubkey: context.counterparty_pubkey,
- root_event_id: context.root_event_id?,
- prev_event_id: context.prev_event_id?,
- payload: envelope.payload,
- },
- ))
- }
- KIND_ORDER_RECEIPT => {
- let envelope = order_receipt_from_event(event).ok()?;
- let context = order_event_context_from_tags(envelope.message_type, &event.tags).ok()?;
- Some(ActiveOrderEvidence::Receipt(RadrootsOrderReceiptRecord {
- event_id: active_event_id(event)?,
- author_pubkey: active_author_pubkey(event)?,
- counterparty_pubkey: context.counterparty_pubkey,
- root_event_id: context.root_event_id?,
- prev_event_id: context.prev_event_id?,
- payload: envelope.payload,
- }))
- }
- KIND_ORDER_PAYMENT => {
- let envelope = order_payment_record_from_event(event).ok()?;
- let context = order_event_context_from_tags(envelope.message_type, &event.tags).ok()?;
- Some(ActiveOrderEvidence::Payment(
- RadrootsOrderPaymentEventRecord {
- event_id: active_event_id(event)?,
- author_pubkey: active_author_pubkey(event)?,
- counterparty_pubkey: context.counterparty_pubkey,
- root_event_id: context.root_event_id?,
- prev_event_id: context.prev_event_id?,
- payload: envelope.payload,
- },
- ))
- }
- KIND_ORDER_SETTLEMENT => {
- let envelope = order_settlement_decision_from_event(event).ok()?;
- let context = order_event_context_from_tags(envelope.message_type, &event.tags).ok()?;
- Some(ActiveOrderEvidence::Settlement(
- RadrootsOrderSettlementRecord {
- event_id: active_event_id(event)?,
- author_pubkey: active_author_pubkey(event)?,
- counterparty_pubkey: context.counterparty_pubkey,
- root_event_id: context.root_event_id?,
- prev_event_id: context.prev_event_id?,
- payload: envelope.payload,
- },
- ))
- }
_ => None,
}
}
@@ -3321,7 +3183,11 @@ fn active_order_revision_status(
revision_proposals: &[RadrootsOrderRevisionProposalRecord],
revision_decisions: &[RadrootsOrderRevisionDecisionRecord],
) -> TradeRevisionStatus {
- let Some(mut parent_event_id) = projection.decision_event_id.clone() else {
+ let Some(mut parent_event_id) = projection
+ .decision_event_id
+ .clone()
+ .or_else(|| projection.request_event_id.clone())
+ else {
return TradeRevisionStatus::None;
};
let mut status = TradeRevisionStatus::None;
@@ -3865,11 +3731,11 @@ mod tests {
use std::collections::BTreeSet;
use radroots_app_view::{
- BuyerContext, BuyerOrderStatus, FarmId, FarmOrderMethod, OrderFulfillmentAction, OrderId,
- OrderPrimaryAction, OrderStatus, OrdersFilter, OrdersScreenQueryState,
- ProductAvailabilityState, ProductId, TradeFulfillmentStatus, TradeInventoryStatus,
- TradePaymentDisplayStatus, TradeRevisionStatus, TradeValidationReceiptProofSystem,
- TradeValidationReceiptResult, TradeValidationReceiptType, TradeWorkflowSource,
+ BuyerContext, BuyerOrderStatus, FarmId, FarmOrderMethod, OrderId, OrderStatus,
+ OrdersFilter, OrdersScreenQueryState, ProductAvailabilityState, ProductId,
+ TradeAgreementStatus, TradeInventoryStatus, TradeRevisionStatus,
+ TradeValidationReceiptProofSystem, TradeValidationReceiptResult,
+ TradeValidationReceiptType, TradeWorkflowSource,
};
use radroots_core::{
RadrootsCoreCurrency, RadrootsCoreDecimal, RadrootsCoreMoney, RadrootsCoreUnit,
@@ -3877,29 +3743,21 @@ mod tests {
use radroots_events::{
RadrootsNostrEvent, RadrootsNostrEventPtr,
ids::{
- RadrootsEconomicsDigest, RadrootsEventId, RadrootsInventoryBinId,
- RadrootsListingAddress, RadrootsOrderId, RadrootsOrderQuoteId, RadrootsOrderRevisionId,
- RadrootsPublicKey,
+ RadrootsEventId, RadrootsInventoryBinId, RadrootsListingAddress, RadrootsOrderId,
+ RadrootsOrderQuoteId, RadrootsOrderRevisionId, RadrootsPublicKey,
},
- kinds::KIND_ORDER_RECEIPT,
order::{
RadrootsOrderCancellation, RadrootsOrderDecision, RadrootsOrderDecisionOutcome,
RadrootsOrderEconomicItem, RadrootsOrderEconomicLine, RadrootsOrderEconomics,
- RadrootsOrderFulfillmentState, RadrootsOrderFulfillmentUpdate,
- RadrootsOrderInventoryCommitment, RadrootsOrderItem, RadrootsOrderPaymentMethod,
- RadrootsOrderPaymentRecord, RadrootsOrderPricingBasis, RadrootsOrderReceipt,
+ RadrootsOrderInventoryCommitment, RadrootsOrderItem, RadrootsOrderPricingBasis,
RadrootsOrderRequest, RadrootsOrderRevisionDecision, RadrootsOrderRevisionOutcome,
- RadrootsOrderRevisionProposal, RadrootsOrderSettlementDecision,
- RadrootsOrderSettlementOutcome,
+ RadrootsOrderRevisionProposal,
},
};
use radroots_events_codec::{
order::{
- order_cancellation_event_build, order_decision_event_build,
- order_fulfillment_update_event_build, order_payment_record_event_build,
- order_receipt_event_build, order_request_event_build,
+ order_cancellation_event_build, order_decision_event_build, order_request_event_build,
order_revision_decision_event_build, order_revision_proposal_event_build,
- order_settlement_decision_event_build,
},
wire::WireEventParts,
};
@@ -3908,14 +3766,11 @@ mod tests {
LocalRecordStatus, PublishOutboxStatus, RelayDeliveryEvidence, SourceRuntime,
};
use radroots_sql_core::SqliteExecutor;
- use radroots_trade::{
- order::radroots_order_economics_digest,
- validation_receipt::{
- RadrootsTradeValidationReceipt, RadrootsValidationReceiptProof,
- RadrootsValidationReceiptProofSystem, RadrootsValidationReceiptResult,
- RadrootsValidationReceiptStatement, RadrootsValidationReceiptType,
- VALIDATION_RECEIPT_DOMAIN, VALIDATION_RECEIPT_VERSION, validation_receipt_event_build,
- },
+ use radroots_trade::validation_receipt::{
+ RadrootsTradeValidationReceipt, RadrootsValidationReceiptProof,
+ RadrootsValidationReceiptProofSystem, RadrootsValidationReceiptResult,
+ RadrootsValidationReceiptStatement, RadrootsValidationReceiptType,
+ VALIDATION_RECEIPT_DOMAIN, VALIDATION_RECEIPT_VERSION, validation_receipt_event_build,
};
use rusqlite::params;
use serde_json::json;
@@ -4418,10 +4273,6 @@ mod tests {
raw.parse().expect("valid listing address")
}
- fn typed_economics_digest(raw: &str) -> RadrootsEconomicsDigest {
- raw.parse().expect("valid economics digest")
- }
-
fn listing_event_ptr(event_id: &str) -> RadrootsNostrEventPtr {
RadrootsNostrEventPtr {
id: test_event_id_seed(event_id),
@@ -4560,22 +4411,6 @@ mod tests {
}
}
- fn fulfillment_update_payload(
- order_id: &str,
- listing_addr: &str,
- buyer_pubkey: &str,
- seller_pubkey: &str,
- status: RadrootsOrderFulfillmentState,
- ) -> RadrootsOrderFulfillmentUpdate {
- RadrootsOrderFulfillmentUpdate {
- order_id: typed_order_id(order_id),
- listing_addr: typed_listing_addr(listing_addr),
- buyer_pubkey: typed_pubkey(buyer_pubkey),
- seller_pubkey: typed_pubkey(seller_pubkey),
- status,
- }
- }
-
fn order_cancel_payload(
order_id: &str,
listing_addr: &str,
@@ -4591,38 +4426,6 @@ mod tests {
}
}
- fn buyer_receipt_payload(
- order_id: &str,
- listing_addr: &str,
- buyer_pubkey: &str,
- seller_pubkey: &str,
- received: bool,
- ) -> RadrootsOrderReceipt {
- RadrootsOrderReceipt {
- order_id: typed_order_id(order_id),
- listing_addr: typed_listing_addr(listing_addr),
- buyer_pubkey: typed_pubkey(buyer_pubkey),
- seller_pubkey: typed_pubkey(seller_pubkey),
- received,
- issue: (!received).then(|| "items need review".to_owned()),
- received_at: 1_777_665_700,
- }
- }
-
- struct ActiveOrderReadyFixture {
- app_store: AppSqliteStore,
- events: LocalEventsStore<SqliteExecutor>,
- buyer_context: BuyerContext,
- seller_farm_id: FarmId,
- order_id: OrderId,
- order_id_raw: String,
- listing_addr: String,
- buyer_pubkey: String,
- seller_pubkey: String,
- request_event_id: String,
- fulfillment_event_id: String,
- }
-
struct ValidationReceiptOrderFixture {
app_store: AppSqliteStore,
events: LocalEventsStore<SqliteExecutor>,
@@ -4638,145 +4441,6 @@ mod tests {
decision_event_id: String,
}
- fn active_order_ready_fixture(label: &str) -> ActiveOrderReadyFixture {
- let app_store =
- AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store");
- let events = local_events_store();
- let farm_key = "DDDDDDDDDDDDDDDDDDDDDD";
- let listing_key = "AAAAAAAAAAAAAAAAAAAAAw";
- let seller_pubkey = test_pubkey(format!("{label}-seller").as_str());
- let buyer_pubkey = test_pubkey(format!("{label}-buyer").as_str());
- let order_id_raw = format!("{label}-order");
- let listing_addr = format!("30402:{seller_pubkey}:{listing_key}");
- events
- .append_record(&signed_market_listing_record(
- format!("{label}-listing-record").as_str(),
- seller_pubkey.as_str(),
- farm_key,
- listing_key,
- "Lifecycle Eggs",
- "9",
- "active",
- "pickup",
- "North barn pickup",
- 4_102_444_800,
- 4_102_531_200,
- LocalRecordStatus::Published,
- PublishOutboxStatus::Acknowledged,
- ))
- .expect("append signed listing");
- app_store
- .import_shared_local_events_from_store(&events)
- .expect("import signed listing");
-
- let request_payload = order_request_payload(
- order_id_raw.as_str(),
- listing_addr.as_str(),
- buyer_pubkey.as_str(),
- seller_pubkey.as_str(),
- );
- let request_parts = order_request_event_build(
- &listing_event_ptr(format!("{label}-listing-event").as_str()),
- &request_payload,
- )
- .expect("build lifecycle order request");
- let request_event = event_from_parts(
- format!("{label}-request-event").as_str(),
- buyer_pubkey.as_str(),
- request_parts,
- );
- events
- .append_record(&signed_order_event_record(
- format!("app:signed_event:{label}:request").as_str(),
- &request_event,
- listing_addr.as_str(),
- SourceRuntime::App,
- Some("acct_lifecycle"),
- ))
- .expect("append lifecycle order request");
- app_store
- .import_shared_local_events_from_store(&events)
- .expect("import lifecycle order request");
-
- let order_id = projected_order_id(order_id_raw.as_str(), buyer_pubkey.as_str());
- let buyer_context = BuyerContext::account("acct_lifecycle");
- let seller_farm_id = deterministic_farm_id(Some(seller_pubkey.as_str()), farm_key);
- let decision_payload = accepted_order_decision_payload(
- order_id_raw.as_str(),
- listing_addr.as_str(),
- buyer_pubkey.as_str(),
- seller_pubkey.as_str(),
- );
- let decision_parts = order_decision_event_build(
- &typed_event_id(request_event.id.as_str()),
- &typed_event_id(request_event.id.as_str()),
- &decision_payload,
- )
- .expect("build lifecycle order decision");
- let decision_event = event_from_parts(
- format!("{label}-decision-event").as_str(),
- seller_pubkey.as_str(),
- decision_parts,
- );
- events
- .append_record(&signed_order_event_record(
- format!("cli:signed_event:{label}:decision").as_str(),
- &decision_event,
- listing_addr.as_str(),
- SourceRuntime::Cli,
- None,
- ))
- .expect("append lifecycle order decision");
- app_store
- .import_shared_local_events_from_store(&events)
- .expect("import lifecycle order decision");
-
- let fulfillment_payload = fulfillment_update_payload(
- order_id_raw.as_str(),
- listing_addr.as_str(),
- buyer_pubkey.as_str(),
- seller_pubkey.as_str(),
- RadrootsOrderFulfillmentState::ReadyForPickup,
- );
- let fulfillment_parts = order_fulfillment_update_event_build(
- &typed_event_id(request_event.id.as_str()),
- &typed_event_id(decision_event.id.as_str()),
- &fulfillment_payload,
- )
- .expect("build lifecycle fulfillment update");
- let fulfillment_event = event_from_parts(
- format!("{label}-fulfillment-event").as_str(),
- seller_pubkey.as_str(),
- fulfillment_parts,
- );
- events
- .append_record(&signed_order_event_record(
- format!("cli:signed_event:{label}:fulfillment").as_str(),
- &fulfillment_event,
- listing_addr.as_str(),
- SourceRuntime::Cli,
- None,
- ))
- .expect("append lifecycle fulfillment");
- app_store
- .import_shared_local_events_from_store(&events)
- .expect("import lifecycle fulfillment");
-
- ActiveOrderReadyFixture {
- app_store,
- events,
- buyer_context,
- seller_farm_id,
- order_id,
- order_id_raw,
- listing_addr,
- buyer_pubkey,
- seller_pubkey,
- request_event_id: request_event.id,
- fulfillment_event_id: fulfillment_event.id,
- }
- }
-
fn validation_receipt_order_fixture(label: &str) -> ValidationReceiptOrderFixture {
let app_store =
AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store");
@@ -4886,68 +4550,6 @@ mod tests {
}
}
- fn payment_recorded_payload(
- request: &RadrootsOrderRequest,
- root_event_id: &str,
- previous_event_id: &str,
- agreement_event_id: &str,
- ) -> RadrootsOrderPaymentRecord {
- RadrootsOrderPaymentRecord {
- order_id: request.order_id.clone(),
- listing_addr: request.listing_addr.clone(),
- buyer_pubkey: request.buyer_pubkey.clone(),
- seller_pubkey: request.seller_pubkey.clone(),
- root_event_id: typed_event_id(root_event_id),
- previous_event_id: typed_event_id(previous_event_id),
- agreement_event_id: typed_event_id(agreement_event_id),
- quote_id: request.economics.quote_id.clone(),
- quote_version: request.economics.quote_version,
- economics_digest: typed_economics_digest(
- radroots_order_economics_digest(&request.economics)
- .expect("order economics digest should encode")
- .as_str(),
- ),
- amount: request.economics.total.amount,
- currency: request.economics.total.currency,
- method: RadrootsOrderPaymentMethod::ManualTransfer,
- reference: Some("manual reference".to_owned()),
- paid_at: Some(1_777_665_800),
- }
- }
-
- fn settlement_decision_payload(
- request: &RadrootsOrderRequest,
- root_event_id: &str,
- previous_event_id: &str,
- agreement_event_id: &str,
- payment_event_id: &str,
- decision: RadrootsOrderSettlementOutcome,
- ) -> RadrootsOrderSettlementDecision {
- let reason = (decision == RadrootsOrderSettlementOutcome::Rejected)
- .then(|| "reference mismatch".to_owned());
- RadrootsOrderSettlementDecision {
- order_id: request.order_id.clone(),
- listing_addr: request.listing_addr.clone(),
- buyer_pubkey: request.buyer_pubkey.clone(),
- seller_pubkey: request.seller_pubkey.clone(),
- root_event_id: typed_event_id(root_event_id),
- previous_event_id: typed_event_id(previous_event_id),
- agreement_event_id: typed_event_id(agreement_event_id),
- payment_event_id: typed_event_id(payment_event_id),
- quote_id: request.economics.quote_id.clone(),
- quote_version: request.economics.quote_version,
- economics_digest: typed_economics_digest(
- radroots_order_economics_digest(&request.economics)
- .expect("order economics digest should encode")
- .as_str(),
- ),
- amount: request.economics.total.amount,
- currency: request.economics.total.currency,
- decision,
- reason,
- }
- }
-
fn event_from_parts(event_id: &str, author: &str, parts: WireEventParts) -> RadrootsNostrEvent {
let event_id = event_id
.parse::<RadrootsEventId>()
@@ -5465,66 +5067,16 @@ mod tests {
assert_eq!(decision_report.imported_records, 1);
assert_eq!(buyer_orders.rows.len(), 1);
assert_eq!(buyer_orders.rows[0].status, BuyerOrderStatus::Scheduled);
- assert_eq!(
- buyer_orders.rows[0].workflow.payment,
- TradePaymentDisplayStatus::NotRecorded
- );
assert_eq!(buyer_detail.status, BuyerOrderStatus::Scheduled);
assert_eq!(seller_orders.rows[0].status, OrderStatus::Scheduled);
-
- let payment_payload = payment_recorded_payload(
- &request_payload,
- request_event.id.as_str(),
- decision_event.id.as_str(),
- decision_event.id.as_str(),
+ assert_eq!(buyer_detail.workflow, buyer_orders.rows[0].workflow);
+ assert_eq!(
+ seller_orders.rows[0].workflow,
+ buyer_orders.rows[0].workflow
);
- let payment_parts = order_payment_record_event_build(
- &typed_event_id(request_event.id.as_str()),
- &typed_event_id(decision_event.id.as_str()),
- &payment_payload,
- )
- .expect("build payment recorded event");
- let payment_event =
- event_from_parts("buyer-order-payment-event", buyer_pubkey, payment_parts);
- events
- .append_record(&signed_order_event_record(
- "app:signed_event:order-payment:buyer",
- &payment_event,
- listing_addr.as_str(),
- SourceRuntime::App,
- Some("acct_buyer"),
- ))
- .expect("append payment recorded event");
-
- let payment_report = app_store
- .import_shared_local_events_from_store(&events)
- .expect("import payment recorded event");
- let buyer_orders = app_store
- .load_buyer_orders(&buyer_context)
- .expect("load buyer orders after payment");
- let buyer_detail = app_store
- .load_buyer_order_detail(&buyer_context, order_id)
- .expect("load buyer order detail after payment")
- .expect("buyer order detail after payment");
- let seller_orders = app_store
- .load_orders_list(
- farm_id,
- &OrdersScreenQueryState {
- filter: OrdersFilter::All,
- fulfillment_window_id: None,
- },
- )
- .expect("load seller orders after payment");
- let seller_detail = app_store
- .load_order_detail(farm_id, order_id)
- .expect("load seller order detail after payment")
- .expect("seller order detail after payment");
-
- assert_eq!(payment_report.imported_records, 1);
- assert_eq!(buyer_orders.rows[0].status, BuyerOrderStatus::Scheduled);
assert_eq!(
- buyer_orders.rows[0].workflow.payment,
- TradePaymentDisplayStatus::Pending
+ buyer_orders.rows[0].workflow.inventory,
+ TradeInventoryStatus::Reserved
);
assert_eq!(
buyer_orders.rows[0].workflow.provenance.primary_source,
@@ -5538,78 +5090,10 @@ mod tests {
.as_deref(),
Some(decision_event.id.as_str())
);
- assert_eq!(buyer_detail.payment, TradePaymentDisplayStatus::Pending);
- assert_eq!(buyer_detail.workflow, buyer_orders.rows[0].workflow);
- assert_eq!(
- seller_orders.rows[0].workflow.payment,
- TradePaymentDisplayStatus::Pending
- );
- assert_eq!(seller_detail.payment, TradePaymentDisplayStatus::Pending);
-
- let settlement_payload = settlement_decision_payload(
- &request_payload,
- request_event.id.as_str(),
- payment_event.id.as_str(),
- decision_event.id.as_str(),
- payment_event.id.as_str(),
- RadrootsOrderSettlementOutcome::Accepted,
- );
- let settlement_parts = order_settlement_decision_event_build(
- &typed_event_id(request_event.id.as_str()),
- &typed_event_id(payment_event.id.as_str()),
- &settlement_payload,
- )
- .expect("build settlement decision event");
- let settlement_event = event_from_parts(
- "buyer-order-settlement-event",
- seller_pubkey,
- settlement_parts,
- );
- events
- .append_record(&signed_order_event_record(
- "cli:signed_event:order-settlement:buyer",
- &settlement_event,
- listing_addr.as_str(),
- SourceRuntime::Cli,
- None,
- ))
- .expect("append settlement decision event");
-
- let settlement_report = app_store
- .import_shared_local_events_from_store(&events)
- .expect("import settlement decision event");
- let buyer_orders = app_store
- .load_buyer_orders(&buyer_context)
- .expect("load buyer orders after settlement");
- let buyer_detail = app_store
- .load_buyer_order_detail(&buyer_context, order_id)
- .expect("load buyer order detail after settlement")
- .expect("buyer order detail after settlement");
- let seller_orders = app_store
- .load_orders_list(
- farm_id,
- &OrdersScreenQueryState {
- filter: OrdersFilter::All,
- fulfillment_window_id: None,
- },
- )
- .expect("load seller orders after settlement");
- let seller_detail = app_store
- .load_order_detail(farm_id, order_id)
- .expect("load seller order detail after settlement")
- .expect("seller order detail after settlement");
-
- assert_eq!(settlement_report.imported_records, 1);
- assert_eq!(
- buyer_orders.rows[0].workflow.payment,
- TradePaymentDisplayStatus::Settled
- );
- assert_eq!(buyer_detail.payment, TradePaymentDisplayStatus::Settled);
assert_eq!(
- seller_orders.rows[0].workflow.payment,
- TradePaymentDisplayStatus::Settled
+ buyer_orders.rows[0].workflow.economics.total_minor_units,
+ Some(1600)
);
- assert_eq!(seller_detail.payment, TradePaymentDisplayStatus::Settled);
}
#[test]
@@ -5744,7 +5228,7 @@ mod tests {
}
#[test]
- fn active_order_fulfillment_and_receipt_project_through_cli_reducer_state() {
+ fn active_order_decision_projects_agreement_state_through_cli_reducer() {
let app_store =
AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store");
let events = local_events_store();
@@ -5806,8 +5290,6 @@ mod tests {
.import_shared_local_events_from_store(&events)
.expect("import lifecycle order request");
- let order_id = projected_order_id(order_id_raw, buyer_pubkey);
- let buyer_context = BuyerContext::account("acct_lifecycle");
let seller_farm_id = deterministic_farm_id(Some(seller_pubkey), farm_key);
let decision_payload = accepted_order_decision_payload(
order_id_raw,
@@ -5849,216 +5331,10 @@ mod tests {
.expect("load lifecycle seller orders after decision");
assert_eq!(seller_orders.rows[0].status, OrderStatus::Scheduled);
assert_eq!(
- seller_orders.rows[0].primary_action,
- Some(OrderPrimaryAction::PublishPreparing)
- );
- assert_eq!(
- seller_orders.rows[0].fulfillment_actions,
- OrderFulfillmentAction::ALL.to_vec()
- );
-
- let fulfillment_payload = fulfillment_update_payload(
- order_id_raw,
- listing_addr.as_str(),
- buyer_pubkey,
- seller_pubkey,
- RadrootsOrderFulfillmentState::ReadyForPickup,
- );
- let fulfillment_parts = order_fulfillment_update_event_build(
- &typed_event_id(request_event.id.as_str()),
- &typed_event_id(decision_event.id.as_str()),
- &fulfillment_payload,
- )
- .expect("build lifecycle fulfillment update");
- let fulfillment_event = event_from_parts(
- "active-lifecycle-fulfillment-event",
- seller_pubkey,
- fulfillment_parts,
- );
- events
- .append_record(&signed_order_event_record(
- "cli:signed_event:active-lifecycle:fulfillment",
- &fulfillment_event,
- listing_addr.as_str(),
- SourceRuntime::Cli,
- None,
- ))
- .expect("append lifecycle fulfillment");
- app_store
- .import_shared_local_events_from_store(&events)
- .expect("import lifecycle fulfillment");
- let buyer_orders = app_store
- .load_buyer_orders(&buyer_context)
- .expect("load lifecycle buyer orders after fulfillment");
- let seller_orders = app_store
- .load_orders_list(
- seller_farm_id,
- &OrdersScreenQueryState {
- filter: OrdersFilter::All,
- fulfillment_window_id: None,
- },
- )
- .expect("load lifecycle seller orders after fulfillment");
- assert_eq!(buyer_orders.rows[0].status, BuyerOrderStatus::Ready);
- assert_eq!(seller_orders.rows[0].status, OrderStatus::Packed);
- assert_eq!(
- seller_orders.rows[0].workflow.fulfillment,
- Some(TradeFulfillmentStatus::ReadyForPickup)
- );
- assert_eq!(
seller_orders.rows[0].workflow.inventory,
TradeInventoryStatus::Reserved
);
- assert_eq!(
- seller_orders.rows[0].primary_action,
- Some(OrderPrimaryAction::PublishDelivered)
- );
- assert_eq!(
- seller_orders.rows[0].fulfillment_actions,
- OrderFulfillmentAction::ALL.to_vec()
- );
-
- let receipt_payload = buyer_receipt_payload(
- order_id_raw,
- listing_addr.as_str(),
- buyer_pubkey,
- seller_pubkey,
- true,
- );
- let receipt_parts = order_receipt_event_build(
- &typed_event_id(request_event.id.as_str()),
- &typed_event_id(fulfillment_event.id.as_str()),
- &receipt_payload,
- )
- .expect("build lifecycle buyer receipt");
- let receipt_event = event_from_parts(
- "active-lifecycle-receipt-event",
- buyer_pubkey,
- receipt_parts,
- );
- events
- .append_record(&signed_order_event_record(
- "app:signed_event:active-lifecycle:receipt",
- &receipt_event,
- listing_addr.as_str(),
- SourceRuntime::App,
- Some("acct_lifecycle"),
- ))
- .expect("append lifecycle buyer receipt");
- app_store
- .import_shared_local_events_from_store(&events)
- .expect("import lifecycle buyer receipt");
- let buyer_detail = app_store
- .load_buyer_order_detail(&buyer_context, order_id)
- .expect("load lifecycle buyer detail")
- .expect("lifecycle buyer detail");
- let seller_orders = app_store
- .load_orders_list(
- seller_farm_id,
- &OrdersScreenQueryState {
- filter: OrdersFilter::All,
- fulfillment_window_id: None,
- },
- )
- .expect("load lifecycle seller orders after receipt");
- assert_eq!(buyer_detail.status, BuyerOrderStatus::Completed);
- let buyer_receipt = buyer_detail
- .workflow
- .receipt
- .as_ref()
- .expect("buyer receipt projection");
- assert_eq!(buyer_receipt.event_id, receipt_event.id);
- assert!(buyer_receipt.received);
- assert!(buyer_receipt.issue.is_none());
- assert_eq!(buyer_receipt.received_at, receipt_payload.received_at);
- assert_eq!(seller_orders.rows[0].status, OrderStatus::Completed);
- let seller_receipt = seller_orders.rows[0]
- .workflow
- .receipt
- .as_ref()
- .expect("seller receipt projection");
- assert_eq!(seller_receipt.event_id, receipt_event.id);
- assert!(seller_receipt.received);
- assert!(seller_receipt.issue.is_none());
- assert_eq!(seller_receipt.received_at, receipt_payload.received_at);
assert_eq!(seller_orders.rows[0].primary_action, None);
- assert_eq!(seller_orders.rows[0].fulfillment_actions, Vec::new());
- }
-
- #[test]
- fn active_order_issue_receipt_projects_through_cli_reducer_state() {
- let fixture = active_order_ready_fixture("active-lifecycle-issue-receipt");
- let receipt_payload = buyer_receipt_payload(
- fixture.order_id_raw.as_str(),
- fixture.listing_addr.as_str(),
- fixture.buyer_pubkey.as_str(),
- fixture.seller_pubkey.as_str(),
- false,
- );
- let receipt_parts = order_receipt_event_build(
- &typed_event_id(fixture.request_event_id.as_str()),
- &typed_event_id(fixture.fulfillment_event_id.as_str()),
- &receipt_payload,
- )
- .expect("build lifecycle buyer issue receipt");
- let receipt_event = event_from_parts(
- "active-lifecycle-issue-receipt-event",
- fixture.buyer_pubkey.as_str(),
- receipt_parts,
- );
- fixture
- .events
- .append_record(&signed_order_event_record(
- "app:signed_event:active-lifecycle:issue-receipt",
- &receipt_event,
- fixture.listing_addr.as_str(),
- SourceRuntime::App,
- Some("acct_lifecycle"),
- ))
- .expect("append lifecycle buyer issue receipt");
- fixture
- .app_store
- .import_shared_local_events_from_store(&fixture.events)
- .expect("import lifecycle buyer issue receipt");
-
- let buyer_detail = fixture
- .app_store
- .load_buyer_order_detail(&fixture.buyer_context, fixture.order_id)
- .expect("load lifecycle buyer issue detail")
- .expect("lifecycle buyer issue detail");
- let seller_orders = fixture
- .app_store
- .load_orders_list(
- fixture.seller_farm_id,
- &OrdersScreenQueryState {
- filter: OrdersFilter::All,
- fulfillment_window_id: None,
- },
- )
- .expect("load lifecycle seller orders after issue receipt");
-
- assert_eq!(buyer_detail.status, BuyerOrderStatus::NeedsReview);
- let buyer_receipt = buyer_detail
- .workflow
- .receipt
- .as_ref()
- .expect("buyer issue receipt projection");
- assert_eq!(buyer_receipt.event_id, receipt_event.id);
- assert!(!buyer_receipt.received);
- assert_eq!(buyer_receipt.issue.as_deref(), Some("items need review"));
- assert_eq!(buyer_receipt.received_at, receipt_payload.received_at);
- assert_eq!(seller_orders.rows[0].status, OrderStatus::NeedsReview);
- let seller_receipt = seller_orders.rows[0]
- .workflow
- .receipt
- .as_ref()
- .expect("seller issue receipt projection");
- assert_eq!(seller_receipt.event_id, receipt_event.id);
- assert!(!seller_receipt.received);
- assert_eq!(seller_receipt.issue.as_deref(), Some("items need review"));
- assert_eq!(seller_receipt.received_at, receipt_payload.received_at);
- assert_eq!(seller_orders.rows[0].primary_action, None);
- assert_eq!(seller_orders.rows[0].fulfillment_actions, Vec::new());
}
#[test]
@@ -6137,24 +5413,7 @@ mod tests {
assert_eq!(buyer_detail.status, BuyerOrderStatus::Scheduled);
assert_eq!(seller_detail.status, OrderStatus::Scheduled);
- assert!(buyer_detail.workflow.receipt.is_none());
- assert!(seller_detail.workflow.receipt.is_none());
- assert_eq!(
- buyer_detail.workflow.payment,
- TradePaymentDisplayStatus::NotRecorded
- );
- assert_eq!(
- seller_detail.workflow.payment,
- TradePaymentDisplayStatus::NotRecorded
- );
- assert_eq!(
- seller_detail.primary_action,
- Some(OrderPrimaryAction::PublishPreparing)
- );
- assert_eq!(
- seller_detail.fulfillment_actions,
- OrderFulfillmentAction::ALL.to_vec()
- );
+ assert_eq!(seller_detail.primary_action, None);
assert_eq!(buyer_detail.validation_receipts.len(), 2);
assert_eq!(
buyer_detail.validation_receipts,
@@ -6335,8 +5594,6 @@ mod tests {
);
assert_eq!(buyer_detail.status, BuyerOrderStatus::Placed);
assert_eq!(seller_detail.status, OrderStatus::NeedsAction);
- assert!(buyer_detail.workflow.receipt.is_none());
- assert!(seller_detail.workflow.receipt.is_none());
}
#[test]
@@ -6379,7 +5636,7 @@ mod tests {
RadrootsValidationReceiptResult::Valid,
1_777_665_605,
);
- buyer_kind_candidate.kind = KIND_ORDER_RECEIPT;
+ buyer_kind_candidate.kind = KIND_ORDER_REQUEST as u32;
for (record_id, event) in [
(
@@ -6426,16 +5683,11 @@ mod tests {
assert!(seller_detail.validation_receipts.is_empty());
assert_eq!(buyer_detail.status, BuyerOrderStatus::Scheduled);
assert_eq!(seller_detail.status, OrderStatus::Scheduled);
- assert!(buyer_detail.workflow.receipt.is_none());
- assert!(seller_detail.workflow.receipt.is_none());
- assert_eq!(
- seller_detail.primary_action,
- Some(OrderPrimaryAction::PublishPreparing)
- );
+ assert_eq!(seller_detail.primary_action, None);
}
#[test]
- fn active_order_revision_and_cancellation_project_through_cli_reducer_state() {
+ fn active_order_revision_projects_through_cli_reducer_state() {
let app_store =
AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store");
let events = local_events_store();
@@ -6494,36 +5746,6 @@ mod tests {
.import_shared_local_events_from_store(&events)
.expect("import revision order request");
- let decision_payload = accepted_order_decision_payload(
- order_id_raw,
- listing_addr.as_str(),
- buyer_pubkey,
- seller_pubkey,
- );
- let decision_parts = order_decision_event_build(
- &typed_event_id(request_event.id.as_str()),
- &typed_event_id(request_event.id.as_str()),
- &decision_payload,
- )
- .expect("build revision order decision");
- let decision_event = event_from_parts(
- "active-revision-decision-event",
- seller_pubkey,
- decision_parts,
- );
- events
- .append_record(&signed_order_event_record(
- "cli:signed_event:active-revision:decision",
- &decision_event,
- listing_addr.as_str(),
- SourceRuntime::Cli,
- None,
- ))
- .expect("append revision order decision");
- app_store
- .import_shared_local_events_from_store(&events)
- .expect("import revision order decision");
-
let proposal_payload = revision_proposal_payload(
"revision-1",
order_id_raw,
@@ -6531,11 +5753,11 @@ mod tests {
buyer_pubkey,
seller_pubkey,
request_event.id.as_str(),
- decision_event.id.as_str(),
+ request_event.id.as_str(),
);
let proposal_parts = order_revision_proposal_event_build(
&typed_event_id(request_event.id.as_str()),
- &typed_event_id(decision_event.id.as_str()),
+ &typed_event_id(request_event.id.as_str()),
&proposal_payload,
)
.expect("build revision proposal");
@@ -6569,7 +5791,7 @@ mod tests {
},
)
.expect("load revision seller orders after proposal");
- assert_eq!(seller_orders.rows[0].status, OrderStatus::Scheduled);
+ assert_eq!(seller_orders.rows[0].status, OrderStatus::NeedsAction);
assert_eq!(
seller_orders.rows[0].workflow.revision,
TradeRevisionStatus::ChangeProposed
@@ -6646,6 +5868,67 @@ mod tests {
assert_eq!(seller_detail.economics.total_minor_units, Some(2400));
assert_eq!(buyer_detail.workflow.revision, TradeRevisionStatus::Updated);
assert_eq!(buyer_detail.economics.total_minor_units, Some(2400));
+ }
+
+ #[test]
+ fn active_order_pre_agreement_cancellation_projects_through_cli_reducer_state() {
+ let app_store =
+ AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store");
+ let events = local_events_store();
+ let farm_key = "EEEEEEEEEEEEEEEEEEEEEE";
+ let listing_key = "AAAAAAAAAAAAAAAAAAAAAx";
+ let seller_pubkey = test_pubkey("seller-pubkey");
+ let seller_pubkey = seller_pubkey.as_str();
+ let buyer_pubkey = test_pubkey("app-buyer-pubkey");
+ let buyer_pubkey = buyer_pubkey.as_str();
+ let order_id_raw = "active-cancel-order-1";
+ let listing_addr = format!("30402:{seller_pubkey}:{listing_key}");
+ events
+ .append_record(&signed_market_listing_record(
+ "active-cancel-listing",
+ seller_pubkey,
+ farm_key,
+ listing_key,
+ "Cancellation Eggs",
+ "9",
+ "active",
+ "pickup",
+ "North barn pickup",
+ 4_102_444_800,
+ 4_102_531_200,
+ LocalRecordStatus::Published,
+ PublishOutboxStatus::Acknowledged,
+ ))
+ .expect("append cancellation listing");
+ app_store
+ .import_shared_local_events_from_store(&events)
+ .expect("import cancellation listing");
+
+ let request_payload = order_request_payload(
+ order_id_raw,
+ listing_addr.as_str(),
+ buyer_pubkey,
+ seller_pubkey,
+ );
+ let request_parts = order_request_event_build(
+ &listing_event_ptr("active-cancel-listing-event"),
+ &request_payload,
+ )
+ .expect("build cancellation order request");
+ let request_event =
+ event_from_parts("active-cancel-request-event", buyer_pubkey, request_parts);
+ events
+ .append_record(&signed_order_event_record(
+ "app:signed_event:active-cancel:request",
+ &request_event,
+ listing_addr.as_str(),
+ SourceRuntime::App,
+ Some("acct_cancel"),
+ ))
+ .expect("append cancellation order request");
+ app_store
+ .import_shared_local_events_from_store(&events)
+ .expect("import cancellation order request");
let cancel_payload = order_cancel_payload(
order_id_raw,
@@ -6655,28 +5938,31 @@ mod tests {
);
let cancel_parts = order_cancellation_event_build(
&typed_event_id(request_event.id.as_str()),
- &typed_event_id(revision_decision_event.id.as_str()),
+ &typed_event_id(request_event.id.as_str()),
&cancel_payload,
)
- .expect("build revision cancellation");
- let cancel_event =
- event_from_parts("active-revision-cancel-event", buyer_pubkey, cancel_parts);
+ .expect("build cancellation");
+ let cancel_event = event_from_parts("active-cancel-event", buyer_pubkey, cancel_parts);
events
.append_record(&signed_order_event_record(
- "app:signed_event:active-revision:cancel",
+ "app:signed_event:active-cancel:cancel",
&cancel_event,
listing_addr.as_str(),
SourceRuntime::App,
- Some("acct_revision"),
+ Some("acct_cancel"),
))
- .expect("append revision cancellation");
- app_store
+ .expect("append cancellation");
+ let cancel_report = app_store
.import_shared_local_events_from_store(&events)
- .expect("import revision cancellation");
+ .expect("import cancellation");
+
+ let seller_farm_id = deterministic_farm_id(Some(seller_pubkey), farm_key);
+ let order_id = projected_order_id(order_id_raw, buyer_pubkey);
+ let buyer_context = BuyerContext::account("acct_cancel");
let buyer_detail = app_store
.load_buyer_order_detail(&buyer_context, order_id)
- .expect("load revision buyer detail")
- .expect("revision buyer detail");
+ .expect("load cancellation buyer detail")
+ .expect("cancellation buyer detail");
let seller_orders = app_store
.load_orders_list(
seller_farm_id,
@@ -6685,12 +5971,20 @@ mod tests {
fulfillment_window_id: None,
},
)
- .expect("load revision seller orders after cancellation");
+ .expect("load cancellation seller orders");
+
+ assert_eq!(cancel_report.imported_records, 1);
assert_eq!(buyer_detail.status, BuyerOrderStatus::Declined);
- assert_eq!(buyer_detail.workflow.revision, TradeRevisionStatus::Updated);
+ assert_eq!(
+ buyer_detail.workflow.agreement,
+ TradeAgreementStatus::Cancelled
+ );
assert_eq!(seller_orders.rows[0].status, OrderStatus::Declined);
+ assert_eq!(
+ seller_orders.rows[0].workflow.agreement,
+ TradeAgreementStatus::Cancelled
+ );
assert_eq!(seller_orders.rows[0].primary_action, None);
- assert_eq!(seller_orders.rows[0].fulfillment_actions, Vec::new());
}
#[test]
diff --git a/crates/store/src/lib.rs b/crates/store/src/lib.rs
@@ -1149,9 +1149,23 @@ mod tests {
}
#[test]
- fn workflow_payment_display_schema_accepts_pending_and_settled_states() {
+ fn order_workflow_schema_is_agreement_only() {
let store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("store should open");
let connection = store.connection();
+ assert!(column_exists(connection, "orders", "workflow_agreement"));
+ assert!(column_exists(connection, "orders", "workflow_inventory"));
+ assert!(column_exists(
+ connection,
+ "orders",
+ "workflow_provenance_source"
+ ));
+ assert!(!column_exists(connection, "orders", "workflow_fulfillment"));
+ assert!(!column_exists(connection, "orders", "workflow_payment"));
+ assert!(!column_exists(
+ connection,
+ "orders",
+ "workflow_receipt_event_id"
+ ));
connection
.execute(
"INSERT INTO farms (id, display_name, readiness, created_at, updated_at)
@@ -1159,27 +1173,6 @@ mod tests {
params!["farm_schema"],
)
.expect("farm should insert");
-
- for (order_id, workflow_payment) in [
- ("order_payment_pending", "pending"),
- ("order_payment_settled", "settled"),
- ] {
- connection
- .execute(
- "INSERT INTO orders (
- id,
- farm_id,
- order_number,
- customer_display_name,
- status,
- updated_at,
- workflow_payment
- ) VALUES (?1, 'farm_schema', ?2, 'Buyer', 'scheduled', '2026-01-01T00:00:00Z', ?3)",
- params![order_id, order_id, workflow_payment],
- )
- .expect("expanded workflow payment state should insert");
- }
-
connection
.execute(
"INSERT INTO orders (
@@ -1189,25 +1182,21 @@ mod tests {
customer_display_name,
status,
updated_at,
- workflow_receipt_event_id,
- workflow_receipt_received,
- workflow_receipt_issue,
- workflow_receipt_received_at
+ workflow_agreement,
+ workflow_inventory
) VALUES (
- 'order_issue_receipt',
+ 'order_needs_review',
'farm_schema',
- 'issue receipt',
+ 'needs review',
'Buyer',
'needs_review',
'2026-01-01T00:00:00Z',
- 'receipt-event-1',
- 0,
- 'items need review',
- 1777665700
+ 'needs_review',
+ 'needs_review'
)",
[],
)
- .expect("receipt projection should insert");
+ .expect("agreement-only workflow projection should insert");
let invalid_result = connection.execute(
"INSERT INTO orders (
@@ -1217,37 +1206,11 @@ mod tests {
customer_display_name,
status,
updated_at,
- workflow_payment
- ) VALUES ('order_payment_invalid', 'farm_schema', 'invalid', 'Buyer', 'scheduled', '2026-01-01T00:00:00Z', 'collect')",
+ workflow_agreement
+ ) VALUES ('order_agreement_invalid', 'farm_schema', 'invalid', 'Buyer', 'scheduled', '2026-01-01T00:00:00Z', 'complete')",
[],
);
assert!(invalid_result.is_err());
-
- let invalid_receipt_result = connection.execute(
- "INSERT INTO orders (
- id,
- farm_id,
- order_number,
- customer_display_name,
- status,
- updated_at,
- workflow_receipt_event_id,
- workflow_receipt_received,
- workflow_receipt_received_at
- ) VALUES (
- 'order_receipt_invalid',
- 'farm_schema',
- 'invalid receipt',
- 'Buyer',
- 'needs_review',
- '2026-01-01T00:00:00Z',
- 'receipt-event-invalid',
- 2,
- 1777665700
- )",
- [],
- );
- assert!(invalid_receipt_result.is_err());
}
#[test]
diff --git a/crates/store/src/migration_audit.rs b/crates/store/src/migration_audit.rs
@@ -3,9 +3,8 @@ use std::collections::{BTreeMap, BTreeSet};
use radroots_app_sync::{AppPublishPayload, SyncOperationKind};
use radroots_events::kinds::{
KIND_FARM, KIND_LISTING, KIND_LISTING_DRAFT, KIND_ORDER_CANCELLATION, KIND_ORDER_DECISION,
- KIND_ORDER_FULFILLMENT_UPDATE, KIND_ORDER_PAYMENT_RECORD, KIND_ORDER_RECEIPT,
KIND_ORDER_REQUEST, KIND_ORDER_REVISION_DECISION, KIND_ORDER_REVISION_PROPOSAL,
- KIND_ORDER_SETTLEMENT_DECISION, KIND_TRADE_VALIDATION_RECEIPT,
+ KIND_TRADE_VALIDATION_RECEIPT,
};
use radroots_local_events::{
LocalEventRecord, LocalEventsStore, LocalRecordFamily, LocalRecordStatus, PublishOutboxStatus,
@@ -102,8 +101,6 @@ pub enum AppSdkMigrationAuditClassification {
FailedRecord,
LocalWorkDeferred,
ManualReviewRequired,
- PaymentDeferred,
- SettlementDeferred,
ValidationReceiptDeferred,
Unsupported,
Unknown,
@@ -119,8 +116,6 @@ impl AppSdkMigrationAuditClassification {
Self::FailedRecord => "failed_record",
Self::LocalWorkDeferred => "local_work_deferred",
Self::ManualReviewRequired => "manual_review_required",
- Self::PaymentDeferred => "payment_deferred",
- Self::SettlementDeferred => "settlement_deferred",
Self::ValidationReceiptDeferred => "validation_receipt_deferred",
Self::Unsupported => "unsupported",
Self::Unknown => "unknown",
@@ -686,12 +681,6 @@ fn classify_shared_signed_event(
report: &mut AppSdkMigrationAuditSourceBuilder,
) -> AppSdkMigrationAuditClassification {
match record.event_kind {
- Some(kind) if kind == KIND_ORDER_PAYMENT_RECORD as i64 => {
- AppSdkMigrationAuditClassification::PaymentDeferred
- }
- Some(kind) if kind == KIND_ORDER_SETTLEMENT_DECISION as i64 => {
- AppSdkMigrationAuditClassification::SettlementDeferred
- }
Some(kind) if kind == KIND_TRADE_VALIDATION_RECEIPT as i64 => {
AppSdkMigrationAuditClassification::ValidationReceiptDeferred
}
@@ -795,8 +784,6 @@ fn supported_signed_event_kind(kind: i64) -> bool {
|| value == KIND_ORDER_REVISION_PROPOSAL as i64
|| value == KIND_ORDER_REVISION_DECISION as i64
|| value == KIND_ORDER_CANCELLATION as i64
- || value == KIND_ORDER_FULFILLMENT_UPDATE as i64
- || value == KIND_ORDER_RECEIPT as i64
)
}
@@ -810,10 +797,6 @@ fn shared_signed_event_kind(kind: i64) -> String {
value if value == KIND_ORDER_REVISION_PROPOSAL as i64 => "order_revision_proposal",
value if value == KIND_ORDER_REVISION_DECISION as i64 => "order_revision_decision",
value if value == KIND_ORDER_CANCELLATION as i64 => "order_cancellation",
- value if value == KIND_ORDER_FULFILLMENT_UPDATE as i64 => "order_fulfillment",
- value if value == KIND_ORDER_RECEIPT as i64 => "order_receipt",
- value if value == KIND_ORDER_PAYMENT_RECORD as i64 => "order_payment",
- value if value == KIND_ORDER_SETTLEMENT_DECISION as i64 => "order_settlement",
value if value == KIND_TRADE_VALIDATION_RECEIPT as i64 => "trade_validation_receipt",
_ => "unsupported",
};
@@ -860,10 +843,7 @@ mod tests {
AppFarmProfilePublishPayload, AppPublishContext, AppPublishPayload, PendingSyncOperation,
};
use radroots_app_view::{FarmId, FarmReadiness};
- use radroots_events::kinds::{
- KIND_LISTING, KIND_ORDER_PAYMENT_RECORD, KIND_ORDER_SETTLEMENT_DECISION,
- KIND_TRADE_VALIDATION_RECEIPT,
- };
+ use radroots_events::kinds::{KIND_LISTING, KIND_ORDER_REQUEST, KIND_TRADE_VALIDATION_RECEIPT};
use radroots_local_events::{
LocalEventRecord, LocalEventRecordInput, LocalEventsStore, LocalRecordFamily,
LocalRecordStatus, PublishOutboxStatus, SourceRuntime,
@@ -1196,7 +1176,7 @@ mod tests {
}
#[test]
- fn shared_local_events_audit_defers_payment_and_settlement() {
+ fn shared_local_events_audit_classifies_supported_events_and_validation_receipts() {
let store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app store");
let shared_events = local_events_store();
shared_events
@@ -1215,18 +1195,11 @@ mod tests {
.expect("append listing b");
shared_events
.append_record(&signed_event_record(
- "payment",
- "payment-event",
- KIND_ORDER_PAYMENT_RECORD as i64,
- ))
- .expect("append payment");
- shared_events
- .append_record(&signed_event_record(
- "settlement",
- "settlement-event",
- KIND_ORDER_SETTLEMENT_DECISION as i64,
+ "request",
+ "request-event",
+ KIND_ORDER_REQUEST as i64,
))
- .expect("append settlement");
+ .expect("append request");
shared_events
.append_record(&signed_event_record(
"validation-receipt",
@@ -1253,28 +1226,14 @@ mod tests {
.len(),
before_records
);
- assert_eq!(report.shared_local_events.batch_count, 5);
- assert_eq!(report.shared_local_events.scanned_records, 5);
+ assert_eq!(report.shared_local_events.batch_count, 4);
+ assert_eq!(report.shared_local_events.scanned_records, 4);
assert_eq!(
count_named(
&report.shared_local_events.classification_counts,
AppSdkMigrationAuditClassification::AlreadyRepresentedCandidate.storage_key()
),
- 2
- );
- assert_eq!(
- count_named(
- &report.shared_local_events.classification_counts,
- AppSdkMigrationAuditClassification::PaymentDeferred.storage_key()
- ),
- 1
- );
- assert_eq!(
- count_named(
- &report.shared_local_events.classification_counts,
- AppSdkMigrationAuditClassification::SettlementDeferred.storage_key()
- ),
- 1
+ 3
);
assert_eq!(
count_named(
diff --git a/crates/store/src/migrations.rs b/crates/store/src/migrations.rs
@@ -98,11 +98,11 @@ const MIGRATIONS: &[Migration] = &[
},
Migration {
version: 24,
- sql: include_str!("../migrations/0024_order_workflow_payment_display_states.sql"),
+ sql: include_str!("../migrations/0024_order_workflow_agreement_states.sql"),
},
Migration {
version: 25,
- sql: include_str!("../migrations/0025_order_receipt_display_projection.sql"),
+ sql: include_str!("../migrations/0025_order_workflow_agreement_projection.sql"),
},
Migration {
version: 26,
diff --git a/crates/store/src/repo/buyer.rs b/crates/store/src/repo/buyer.rs
@@ -808,13 +808,7 @@ impl<'a> AppBuyerRepository<'a> {
o.status,
o.workflow_revision,
o.workflow_agreement,
- o.workflow_fulfillment,
- o.workflow_receipt_event_id,
- o.workflow_receipt_received,
- o.workflow_receipt_issue,
- o.workflow_receipt_received_at,
o.workflow_inventory,
- o.workflow_payment,
o.workflow_provenance_source,
o.workflow_provenance_last_event_id,
f.display_name,
@@ -843,19 +837,13 @@ impl<'a> AppBuyerRepository<'a> {
row.get::<_, String>(3)?,
row.get::<_, String>(4)?,
row.get::<_, String>(5)?,
- row.get::<_, Option<String>>(6)?,
- row.get::<_, Option<String>>(7)?,
- row.get::<_, Option<i64>>(8)?,
- row.get::<_, Option<String>>(9)?,
- row.get::<_, Option<i64>>(10)?,
- row.get::<_, String>(11)?,
- row.get::<_, String>(12)?,
- row.get::<_, String>(13)?,
- row.get::<_, Option<String>>(14)?,
- row.get::<_, String>(15)?,
- row.get::<_, Option<String>>(16)?,
- row.get::<_, Option<String>>(17)?,
- row.get::<_, Option<String>>(18)?,
+ row.get::<_, String>(6)?,
+ row.get::<_, String>(7)?,
+ row.get::<_, Option<String>>(8)?,
+ row.get::<_, String>(9)?,
+ row.get::<_, Option<String>>(10)?,
+ row.get::<_, Option<String>>(11)?,
+ row.get::<_, Option<String>>(12)?,
))
})
.map_err(|source| AppSqliteError::Query {
@@ -872,13 +860,7 @@ impl<'a> AppBuyerRepository<'a> {
status,
workflow_revision,
workflow_agreement,
- workflow_fulfillment,
- workflow_receipt_event_id,
- workflow_receipt_received,
- workflow_receipt_issue,
- workflow_receipt_received_at,
workflow_inventory,
- workflow_payment,
workflow_provenance_source,
workflow_provenance_last_event_id,
farm_display_name,
@@ -901,13 +883,7 @@ impl<'a> AppBuyerRepository<'a> {
revision,
economics,
agreement: workflow_agreement,
- fulfillment: workflow_fulfillment,
- receipt_event_id: workflow_receipt_event_id,
- receipt_received: workflow_receipt_received,
- receipt_issue: workflow_receipt_issue,
- receipt_received_at: workflow_receipt_received_at,
inventory: workflow_inventory,
- payment: workflow_payment,
provenance_source: workflow_provenance_source,
provenance_last_event_id: workflow_provenance_last_event_id,
})?;
@@ -968,13 +944,7 @@ impl<'a> AppBuyerRepository<'a> {
o.buyer_order_note,
o.workflow_revision,
o.workflow_agreement,
- o.workflow_fulfillment,
- o.workflow_receipt_event_id,
- o.workflow_receipt_received,
- o.workflow_receipt_issue,
- o.workflow_receipt_received_at,
o.workflow_inventory,
- o.workflow_payment,
o.workflow_provenance_source,
o.workflow_provenance_last_event_id,
f.display_name,
@@ -1000,19 +970,13 @@ impl<'a> AppBuyerRepository<'a> {
row.get::<_, String>(4)?,
row.get::<_, String>(5)?,
row.get::<_, String>(6)?,
- row.get::<_, Option<String>>(7)?,
- row.get::<_, Option<String>>(8)?,
- row.get::<_, Option<i64>>(9)?,
- row.get::<_, Option<String>>(10)?,
- row.get::<_, Option<i64>>(11)?,
- row.get::<_, String>(12)?,
- row.get::<_, String>(13)?,
- row.get::<_, String>(14)?,
- row.get::<_, Option<String>>(15)?,
- row.get::<_, String>(16)?,
- row.get::<_, Option<String>>(17)?,
- row.get::<_, Option<String>>(18)?,
- row.get::<_, Option<String>>(19)?,
+ row.get::<_, String>(7)?,
+ row.get::<_, String>(8)?,
+ row.get::<_, Option<String>>(9)?,
+ row.get::<_, String>(10)?,
+ row.get::<_, Option<String>>(11)?,
+ row.get::<_, Option<String>>(12)?,
+ row.get::<_, Option<String>>(13)?,
))
})
.optional()
@@ -1031,13 +995,7 @@ impl<'a> AppBuyerRepository<'a> {
order_note,
workflow_revision,
workflow_agreement,
- workflow_fulfillment,
- workflow_receipt_event_id,
- workflow_receipt_received,
- workflow_receipt_issue,
- workflow_receipt_received_at,
workflow_inventory,
- workflow_payment,
workflow_provenance_source,
workflow_provenance_last_event_id,
farm_display_name,
@@ -1059,17 +1017,10 @@ impl<'a> AppBuyerRepository<'a> {
revision,
economics: economics.clone(),
agreement: workflow_agreement,
- fulfillment: workflow_fulfillment,
- receipt_event_id: workflow_receipt_event_id,
- receipt_received: workflow_receipt_received,
- receipt_issue: workflow_receipt_issue,
- receipt_received_at: workflow_receipt_received_at,
inventory: workflow_inventory,
- payment: workflow_payment,
provenance_source: workflow_provenance_source,
provenance_last_event_id: workflow_provenance_last_event_id,
})?;
- let payment = workflow.payment;
let validation_receipts = order_validation_receipts(self.connection, order_id)?;
Ok(BuyerOrderDetailProjection {
order_id,
@@ -1084,7 +1035,6 @@ impl<'a> AppBuyerRepository<'a> {
status,
items,
economics,
- payment,
workflow,
validation_receipts,
order_note: empty_string_to_none(order_note),
@@ -2913,7 +2863,6 @@ fn parse_order_status(field: &'static str, value: String) -> Result<OrderStatus,
"packed" => Ok(OrderStatus::Packed),
"completed" => Ok(OrderStatus::Completed),
"declined" => Ok(OrderStatus::Declined),
- "refunded" => Ok(OrderStatus::Refunded),
"needs_review" => Ok(OrderStatus::NeedsReview),
_ => Err(AppSqliteError::DecodeEnum { field, value }),
}
@@ -2997,8 +2946,7 @@ mod tests {
use radroots_app_view::{
BuyerContext, BuyerOrderReviewDisabledReason, BuyerOrderStatus, FarmId, FarmOrderMethod,
FulfillmentWindowId, OrderId, PickupLocationId, ProductId, TradeAgreementStatus,
- TradeFulfillmentStatus, TradeInventoryStatus, TradePaymentDisplayStatus,
- TradeRevisionStatus, TradeWorkflowSource,
+ TradeInventoryStatus, TradeRevisionStatus, TradeWorkflowSource,
};
use rusqlite::{Connection, params};
use serde_json::json;
@@ -3503,10 +3451,6 @@ mod tests {
buyer_order_detail.economics.currency_code.as_deref(),
Some("USD")
);
- assert_eq!(
- buyer_order_detail.payment,
- TradePaymentDisplayStatus::NotRecorded
- );
}
#[test]
@@ -3880,11 +3824,9 @@ mod tests {
connection,
order_id,
"confirmed",
- Some("ready_for_pickup"),
"reserved",
- "recorded",
"local_events",
- Some("payment-event-1"),
+ Some("agreement-event-1"),
);
let list = repository
@@ -3898,24 +3840,18 @@ mod tests {
assert_eq!(list.rows.len(), 1);
assert_eq!(row.workflow.agreement, TradeAgreementStatus::Confirmed);
- assert_eq!(
- row.workflow.fulfillment,
- Some(TradeFulfillmentStatus::ReadyForPickup)
- );
assert_eq!(row.workflow.inventory, TradeInventoryStatus::Reserved);
- assert_eq!(row.workflow.payment, TradePaymentDisplayStatus::Recorded);
assert_eq!(
row.workflow.provenance.primary_source,
TradeWorkflowSource::LocalEvents
);
assert_eq!(
row.workflow.provenance.last_event_id.as_deref(),
- Some("payment-event-1")
+ Some("agreement-event-1")
);
assert_eq!(row.workflow.economics.total_minor_units, Some(1300));
assert_eq!(row.workflow.economics.currency_code.as_deref(), Some("USD"));
assert_eq!(detail.workflow, row.workflow);
- assert_eq!(detail.payment, TradePaymentDisplayStatus::Recorded);
}
#[test]
@@ -3942,18 +3878,14 @@ mod tests {
connection,
order_id,
"confirmed",
- Some("ready_for_pickup"),
"reserved",
- "recorded",
"local_events",
Some("buyer-workflow-event"),
);
for (column, expected_field) in [
("workflow_agreement", "orders.workflow_agreement"),
- ("workflow_fulfillment", "orders.workflow_fulfillment"),
("workflow_inventory", "orders.workflow_inventory"),
- ("workflow_payment", "orders.workflow_payment"),
(
"workflow_provenance_source",
"orders.workflow_provenance_source",
@@ -3963,9 +3895,7 @@ mod tests {
connection,
order_id,
"confirmed",
- Some("ready_for_pickup"),
"reserved",
- "recorded",
"local_events",
Some("buyer-workflow-event"),
);
@@ -4253,9 +4183,7 @@ mod tests {
connection: &Connection,
order_id: OrderId,
agreement: &str,
- fulfillment: Option<&str>,
inventory: &str,
- payment: &str,
provenance_source: &str,
provenance_last_event_id: Option<&str>,
) {
@@ -4263,17 +4191,13 @@ mod tests {
.execute(
"update orders
set workflow_agreement = ?1,
- workflow_fulfillment = ?2,
- workflow_inventory = ?3,
- workflow_payment = ?4,
- workflow_provenance_source = ?5,
- workflow_provenance_last_event_id = ?6
- where id = ?7",
+ workflow_inventory = ?2,
+ workflow_provenance_source = ?3,
+ workflow_provenance_last_event_id = ?4
+ where id = ?5",
params![
agreement,
- fulfillment,
inventory,
- payment,
provenance_source,
provenance_last_event_id,
order_id.to_string(),
@@ -4344,9 +4268,7 @@ mod tests {
.expect("check constraints should disable");
let statement = match column {
"workflow_agreement" => "update orders set workflow_agreement = ?1 where id = ?2",
- "workflow_fulfillment" => "update orders set workflow_fulfillment = ?1 where id = ?2",
"workflow_inventory" => "update orders set workflow_inventory = ?1 where id = ?2",
- "workflow_payment" => "update orders set workflow_payment = ?1 where id = ?2",
"workflow_provenance_source" => {
"update orders set workflow_provenance_source = ?1 where id = ?2"
}
diff --git a/crates/store/src/repo/orders.rs b/crates/store/src/repo/orders.rs
@@ -2,12 +2,12 @@ use std::collections::BTreeMap;
use radroots_app_view::{
FarmId, FulfillmentWindowId, FulfillmentWindowSummary, OrderDetailItemRow,
- OrderDetailProjection, OrderFulfillmentAction, OrderId, OrderPrimaryAction, OrderStatus,
- OrdersFilter, OrdersListProjection, OrdersListRow, OrdersListSummary, OrdersScreenQueryState,
+ OrderDetailProjection, OrderId, OrderPrimaryAction, OrderStatus, OrdersFilter,
+ OrdersListProjection, OrdersListRow, OrdersListSummary, OrdersScreenQueryState,
PackDayOutputCustomerOrder, PackDayOutputOrderState, PackDayOutputPackListEntry,
PackDayOutputProductTotal, PackDayOutputQuantity, PackDayOutputSource, PackDayOutputWindow,
PackDayPackListRow, PackDayProductTotalRow, PackDayProjection, PackDayRosterRow,
- PackDayScreenQueryState, ProductId, TradeFulfillmentStatus, TradeWorkflowProjection,
+ PackDayScreenQueryState, ProductId, TradeWorkflowProjection,
};
use rusqlite::{Connection, OptionalExtension, params};
@@ -80,13 +80,7 @@ impl<'a> AppOrdersRepository<'a> {
o.fulfillment_window_id,
o.workflow_revision,
o.workflow_agreement,
- o.workflow_fulfillment,
- o.workflow_receipt_event_id,
- o.workflow_receipt_received,
- o.workflow_receipt_issue,
- o.workflow_receipt_received_at,
o.workflow_inventory,
- o.workflow_payment,
o.workflow_provenance_source,
o.workflow_provenance_last_event_id,
fw.label,
@@ -107,17 +101,11 @@ impl<'a> AppOrdersRepository<'a> {
row.get::<_, Option<String>>(5)?,
row.get::<_, String>(6)?,
row.get::<_, String>(7)?,
- row.get::<_, Option<String>>(8)?,
- row.get::<_, Option<String>>(9)?,
- row.get::<_, Option<i64>>(10)?,
+ row.get::<_, String>(8)?,
+ row.get::<_, String>(9)?,
+ row.get::<_, Option<String>>(10)?,
row.get::<_, Option<String>>(11)?,
- row.get::<_, Option<i64>>(12)?,
- row.get::<_, String>(13)?,
- row.get::<_, String>(14)?,
- row.get::<_, String>(15)?,
- row.get::<_, Option<String>>(16)?,
- row.get::<_, Option<String>>(17)?,
- row.get::<_, Option<String>>(18)?,
+ row.get::<_, Option<String>>(12)?,
))
},
)
@@ -138,13 +126,7 @@ impl<'a> AppOrdersRepository<'a> {
fulfillment_window_id,
workflow_revision,
workflow_agreement,
- workflow_fulfillment,
- workflow_receipt_event_id,
- workflow_receipt_received,
- workflow_receipt_issue,
- workflow_receipt_received_at,
workflow_inventory,
- workflow_payment,
workflow_provenance_source,
workflow_provenance_last_event_id,
fulfillment_window_label,
@@ -163,17 +145,10 @@ impl<'a> AppOrdersRepository<'a> {
revision,
economics: economics.clone(),
agreement: workflow_agreement,
- fulfillment: workflow_fulfillment,
- receipt_event_id: workflow_receipt_event_id,
- receipt_received: workflow_receipt_received,
- receipt_issue: workflow_receipt_issue,
- receipt_received_at: workflow_receipt_received_at,
inventory: workflow_inventory,
- payment: workflow_payment,
provenance_source: workflow_provenance_source,
provenance_last_event_id: workflow_provenance_last_event_id,
})?;
- let payment = workflow.payment;
let validation_receipts = order_validation_receipts(self.connection, order_id)?;
Ok(OrderDetailProjection {
order_id,
@@ -189,10 +164,8 @@ impl<'a> AppOrdersRepository<'a> {
pickup_location_label: empty_string_to_none(pickup_location_label),
items,
economics,
- payment,
validation_receipts,
primary_action: primary_action_for_order(status, &workflow),
- fulfillment_actions: fulfillment_actions_for_order(status, &workflow),
workflow,
recoveries: Vec::new(),
})
@@ -315,13 +288,7 @@ impl<'a> AppOrdersRepository<'a> {
o.status,
o.workflow_revision,
o.workflow_agreement,
- o.workflow_fulfillment,
- o.workflow_receipt_event_id,
- o.workflow_receipt_received,
- o.workflow_receipt_issue,
- o.workflow_receipt_received_at,
o.workflow_inventory,
- o.workflow_payment,
o.workflow_provenance_source,
o.workflow_provenance_last_event_id,
fw.label,
@@ -353,17 +320,11 @@ impl<'a> AppOrdersRepository<'a> {
row.get::<_, String>(5)?,
row.get::<_, String>(6)?,
row.get::<_, String>(7)?,
- row.get::<_, Option<String>>(8)?,
- row.get::<_, Option<String>>(9)?,
- row.get::<_, Option<i64>>(10)?,
+ row.get::<_, String>(8)?,
+ row.get::<_, String>(9)?,
+ row.get::<_, Option<String>>(10)?,
row.get::<_, Option<String>>(11)?,
- row.get::<_, Option<i64>>(12)?,
- row.get::<_, String>(13)?,
- row.get::<_, String>(14)?,
- row.get::<_, String>(15)?,
- row.get::<_, Option<String>>(16)?,
- row.get::<_, Option<String>>(17)?,
- row.get::<_, Option<String>>(18)?,
+ row.get::<_, Option<String>>(12)?,
))
},
)
@@ -383,13 +344,7 @@ impl<'a> AppOrdersRepository<'a> {
status,
workflow_revision,
workflow_agreement,
- workflow_fulfillment,
- workflow_receipt_event_id,
- workflow_receipt_received,
- workflow_receipt_issue,
- workflow_receipt_received_at,
workflow_inventory,
- workflow_payment,
workflow_provenance_source,
workflow_provenance_last_event_id,
fulfillment_window_label,
@@ -410,13 +365,7 @@ impl<'a> AppOrdersRepository<'a> {
revision,
economics,
agreement: workflow_agreement,
- fulfillment: workflow_fulfillment,
- receipt_event_id: workflow_receipt_event_id,
- receipt_received: workflow_receipt_received,
- receipt_issue: workflow_receipt_issue,
- receipt_received_at: workflow_receipt_received_at,
inventory: workflow_inventory,
- payment: workflow_payment,
provenance_source: workflow_provenance_source,
provenance_last_event_id: workflow_provenance_last_event_id,
})?;
@@ -1187,7 +1136,6 @@ impl OrderRecord {
OrdersFilter::Scheduled => self.status == OrderStatus::Scheduled,
OrdersFilter::Packed => self.status == OrderStatus::Packed,
OrdersFilter::Completed => self.status == OrderStatus::Completed,
- OrdersFilter::Refunded => self.status == OrderStatus::Refunded,
}
}
@@ -1202,7 +1150,6 @@ impl OrderRecord {
pickup_location_label: self.pickup_location_label,
status: self.status,
primary_action: primary_action_for_order(self.status, &self.workflow),
- fulfillment_actions: fulfillment_actions_for_order(self.status, &self.workflow),
workflow: self.workflow,
}
}
@@ -1219,7 +1166,7 @@ fn summarize_orders(records: &[OrderRecord]) -> OrdersListSummary {
OrderStatus::NeedsAction | OrderStatus::NeedsReview => summary.needs_action_orders += 1,
OrderStatus::Scheduled => summary.scheduled_orders += 1,
OrderStatus::Packed => summary.packed_orders += 1,
- OrderStatus::Completed | OrderStatus::Declined | OrderStatus::Refunded => {}
+ OrderStatus::Completed | OrderStatus::Declined => {}
}
}
@@ -1228,45 +1175,18 @@ fn summarize_orders(records: &[OrderRecord]) -> OrdersListSummary {
fn primary_action_for_order(
status: OrderStatus,
- workflow: &TradeWorkflowProjection,
+ _workflow: &TradeWorkflowProjection,
) -> Option<OrderPrimaryAction> {
match status {
OrderStatus::NeedsAction => Some(OrderPrimaryAction::Review),
- OrderStatus::Scheduled | OrderStatus::Packed => match workflow.fulfillment {
- None | Some(TradeFulfillmentStatus::Confirmed | TradeFulfillmentStatus::Preparing) => {
- Some(OrderPrimaryAction::PublishPreparing)
- }
- Some(
- TradeFulfillmentStatus::ReadyForPickup | TradeFulfillmentStatus::OutForDelivery,
- ) => Some(OrderPrimaryAction::PublishDelivered),
- Some(TradeFulfillmentStatus::Delivered | TradeFulfillmentStatus::Cancelled) => None,
- },
- OrderStatus::Completed
+ OrderStatus::Scheduled
+ | OrderStatus::Packed
+ | OrderStatus::Completed
| OrderStatus::Declined
- | OrderStatus::Refunded
| OrderStatus::NeedsReview => None,
}
}
-fn fulfillment_actions_for_order(
- status: OrderStatus,
- workflow: &TradeWorkflowProjection,
-) -> Vec<OrderFulfillmentAction> {
- match (status, workflow.fulfillment) {
- (
- OrderStatus::Scheduled | OrderStatus::Packed,
- None
- | Some(
- TradeFulfillmentStatus::Confirmed
- | TradeFulfillmentStatus::Preparing
- | TradeFulfillmentStatus::ReadyForPickup
- | TradeFulfillmentStatus::OutForDelivery,
- ),
- ) => OrderFulfillmentAction::ALL.to_vec(),
- _ => Vec::new(),
- }
-}
-
fn format_quantity_display(quantity_value: u32, quantity_unit_label: &str) -> String {
if quantity_unit_label.trim().is_empty() {
quantity_value.to_string()
@@ -1321,7 +1241,6 @@ fn parse_order_status(field: &'static str, value: String) -> Result<OrderStatus,
"packed" => Ok(OrderStatus::Packed),
"completed" => Ok(OrderStatus::Completed),
"declined" => Ok(OrderStatus::Declined),
- "refunded" => Ok(OrderStatus::Refunded),
"needs_review" => Ok(OrderStatus::NeedsReview),
_ => Err(AppSqliteError::DecodeEnum { field, value }),
}
@@ -1351,10 +1270,9 @@ fn empty_string_to_none(value: Option<String>) -> Option<String> {
#[cfg(test)]
mod tests {
use radroots_app_view::{
- FarmId, FulfillmentWindowId, OrderFulfillmentAction, OrderId, OrderPrimaryAction,
- OrderStatus, OrdersFilter, OrdersScreenQueryState, PackDayOutputOrderState,
- PackDayProductTotalRow, PackDayScreenQueryState, PickupLocationId, TradeAgreementStatus,
- TradeFulfillmentStatus, TradeInventoryStatus, TradePaymentDisplayStatus,
+ FarmId, FulfillmentWindowId, OrderId, OrderPrimaryAction, OrderStatus, OrdersFilter,
+ OrdersScreenQueryState, PackDayOutputOrderState, PackDayProductTotalRow,
+ PackDayScreenQueryState, PickupLocationId, TradeAgreementStatus, TradeInventoryStatus,
TradeRevisionStatus, TradeWorkflowSource,
};
use rusqlite::{Connection, params};
@@ -1453,7 +1371,7 @@ mod tests {
None,
"R-104",
"Alex",
- "refunded",
+ "needs_review",
"2026-04-17T14:00:00Z",
);
insert_order(
@@ -1573,15 +1491,7 @@ mod tests {
assert_eq!(detail.items[1].quantity_display, "1 bunch");
assert_eq!(detail.economics.total_minor_units, Some(1950));
assert_eq!(detail.economics.currency_code.as_deref(), Some("USD"));
- assert_eq!(detail.payment, TradePaymentDisplayStatus::NotRecorded);
- assert_eq!(
- detail.primary_action,
- Some(OrderPrimaryAction::PublishPreparing)
- );
- assert_eq!(
- detail.fulfillment_actions,
- OrderFulfillmentAction::ALL.to_vec()
- );
+ assert_eq!(detail.primary_action, None);
}
#[test]
@@ -1693,9 +1603,7 @@ mod tests {
connection,
order_id,
"confirmed",
- Some("ready_for_pickup"),
"reserved",
- "recorded",
"local_events",
Some("seller-workflow-event"),
);
@@ -1717,12 +1625,7 @@ mod tests {
assert_eq!(workflow.agreement, TradeAgreementStatus::Confirmed);
assert_eq!(workflow.revision, TradeRevisionStatus::Updated);
- assert_eq!(
- workflow.fulfillment,
- Some(TradeFulfillmentStatus::ReadyForPickup)
- );
assert_eq!(workflow.inventory, TradeInventoryStatus::Reserved);
- assert_eq!(workflow.payment, TradePaymentDisplayStatus::Recorded);
assert_eq!(
workflow.provenance.primary_source,
TradeWorkflowSource::LocalEvents
@@ -1733,84 +1636,9 @@ mod tests {
);
assert_eq!(workflow.economics.total_minor_units, Some(1300));
assert_eq!(workflow.economics.currency_code.as_deref(), Some("USD"));
- assert_eq!(detail.payment, TradePaymentDisplayStatus::Recorded);
assert_eq!(detail.workflow, *workflow);
- assert_eq!(
- list.rows[0].primary_action,
- Some(OrderPrimaryAction::PublishDelivered)
- );
- assert_eq!(
- list.rows[0].fulfillment_actions,
- OrderFulfillmentAction::ALL.to_vec()
- );
- assert_eq!(
- detail.primary_action,
- Some(OrderPrimaryAction::PublishDelivered)
- );
- assert_eq!(
- detail.fulfillment_actions,
- OrderFulfillmentAction::ALL.to_vec()
- );
- }
-
- #[test]
- fn seller_delivered_workflow_exposes_no_duplicate_primary_action() {
- let store = AppSqliteStore::open(DatabaseTarget::InMemory).expect("store should open");
- let connection = store.connection();
- let farm_id = FarmId::new();
- let order_id = OrderId::new();
-
- insert_farm(
- connection,
- farm_id,
- "Willow farm",
- "ready",
- "2026-04-17T08:00:00Z",
- );
- insert_order(
- connection,
- order_id,
- farm_id,
- None,
- "R-101",
- "Casey",
- "packed",
- "2026-04-17T10:00:00Z",
- );
- set_order_workflow_display_projection(
- connection,
- order_id,
- "confirmed",
- Some("delivered"),
- "reserved",
- "not_recorded",
- "local_events",
- Some("seller-delivered-event"),
- );
-
- let list = store
- .load_orders_list(
- farm_id,
- &OrdersScreenQueryState {
- filter: OrdersFilter::Packed,
- fulfillment_window_id: None,
- },
- )
- .expect("seller list should load");
- let detail = store
- .load_order_detail(farm_id, order_id)
- .expect("seller detail should load")
- .expect("seller detail should exist");
-
- assert_eq!(list.rows[0].status, OrderStatus::Packed);
- assert_eq!(
- list.rows[0].workflow.fulfillment,
- Some(TradeFulfillmentStatus::Delivered)
- );
assert_eq!(list.rows[0].primary_action, None);
- assert_eq!(list.rows[0].fulfillment_actions, Vec::new());
assert_eq!(detail.primary_action, None);
- assert_eq!(detail.fulfillment_actions, Vec::new());
}
#[test]
@@ -1841,18 +1669,14 @@ mod tests {
connection,
order_id,
"confirmed",
- Some("ready_for_pickup"),
"reserved",
- "recorded",
"local_events",
Some("seller-workflow-event"),
);
for (column, expected_field) in [
("workflow_agreement", "orders.workflow_agreement"),
- ("workflow_fulfillment", "orders.workflow_fulfillment"),
("workflow_inventory", "orders.workflow_inventory"),
- ("workflow_payment", "orders.workflow_payment"),
(
"workflow_provenance_source",
"orders.workflow_provenance_source",
@@ -1862,9 +1686,7 @@ mod tests {
connection,
order_id,
"confirmed",
- Some("ready_for_pickup"),
"reserved",
- "recorded",
"local_events",
Some("seller-workflow-event"),
);
@@ -2389,9 +2211,7 @@ mod tests {
connection: &Connection,
order_id: OrderId,
agreement: &str,
- fulfillment: Option<&str>,
inventory: &str,
- payment: &str,
provenance_source: &str,
provenance_last_event_id: Option<&str>,
) {
@@ -2399,17 +2219,13 @@ mod tests {
.execute(
"update orders
set workflow_agreement = ?1,
- workflow_fulfillment = ?2,
- workflow_inventory = ?3,
- workflow_payment = ?4,
- workflow_provenance_source = ?5,
- workflow_provenance_last_event_id = ?6
- where id = ?7",
+ workflow_inventory = ?2,
+ workflow_provenance_source = ?3,
+ workflow_provenance_last_event_id = ?4
+ where id = ?5",
params![
agreement,
- fulfillment,
inventory,
- payment,
provenance_source,
provenance_last_event_id,
order_id.to_string(),
@@ -2429,9 +2245,7 @@ mod tests {
.expect("check constraints should disable");
let statement = match column {
"workflow_agreement" => "update orders set workflow_agreement = ?1 where id = ?2",
- "workflow_fulfillment" => "update orders set workflow_fulfillment = ?1 where id = ?2",
"workflow_inventory" => "update orders set workflow_inventory = ?1 where id = ?2",
- "workflow_payment" => "update orders set workflow_payment = ?1 where id = ?2",
"workflow_provenance_source" => {
"update orders set workflow_provenance_source = ?1 where id = ?2"
}
diff --git a/crates/store/src/repo/reminders.rs b/crates/store/src/repo/reminders.rs
@@ -536,7 +536,6 @@ fn parse_reminder_kind(value: String) -> Result<ReminderKind, AppSqliteError> {
"fulfillment_window" => Ok(ReminderKind::FulfillmentWindow),
"order_action" => Ok(ReminderKind::OrderAction),
"missed_pickup_recovery" => Ok(ReminderKind::MissedPickupRecovery),
- "refund_recovery" => Ok(ReminderKind::RefundRecovery),
"sync_impact" => Ok(ReminderKind::SyncImpact),
_ => Err(AppSqliteError::DecodeEnum {
field: "reminder_schedules.reminder_kind",
@@ -586,7 +585,6 @@ fn parse_reminder_delivery_state(value: String) -> Result<ReminderDeliveryState,
fn parse_recovery_kind(value: String) -> Result<RecoveryKind, AppSqliteError> {
match value.as_str() {
"missed_pickup" => Ok(RecoveryKind::MissedPickup),
- "refund_follow_up" => Ok(RecoveryKind::RefundFollowUp),
_ => Err(AppSqliteError::DecodeEnum {
field: "order_recovery_records.recovery_kind",
value,
@@ -718,8 +716,8 @@ mod tests {
farm_id,
&ReminderLogEntryProjection {
reminder_id: second_reminder_id,
- kind: ReminderKind::RefundRecovery,
- title: "Refund follow-up pending".to_owned(),
+ kind: ReminderKind::MissedPickupRecovery,
+ title: "Pickup follow-up pending".to_owned(),
recorded_at: "2026-04-25T13:00:00Z".to_owned(),
delivery_state: ReminderDeliveryState::Acknowledged,
detail: Some("Customer requested a callback.".to_owned()),
diff --git a/crates/store/src/repo/workflow.rs b/crates/store/src/repo/workflow.rs
@@ -1,7 +1,6 @@
use radroots_app_view::{
- OrderId, TradeAgreementStatus, TradeEconomicsProjection, TradeFulfillmentStatus,
- TradeInventoryStatus, TradePaymentDisplayStatus, TradeProvenanceProjection,
- TradeReceiptProjection, TradeRevisionStatus, TradeWorkflowProjection, TradeWorkflowSource,
+ OrderId, TradeAgreementStatus, TradeEconomicsProjection, TradeInventoryStatus,
+ TradeProvenanceProjection, TradeRevisionStatus, TradeWorkflowProjection, TradeWorkflowSource,
};
use crate::AppSqliteError;
@@ -12,13 +11,7 @@ pub(super) struct StoredTradeWorkflowSnapshot {
pub revision: TradeRevisionStatus,
pub economics: TradeEconomicsProjection,
pub agreement: String,
- pub fulfillment: Option<String>,
- pub receipt_event_id: Option<String>,
- pub receipt_received: Option<i64>,
- pub receipt_issue: Option<String>,
- pub receipt_received_at: Option<i64>,
pub inventory: String,
- pub payment: String,
pub provenance_source: String,
pub provenance_last_event_id: Option<String>,
}
@@ -30,19 +23,8 @@ pub(super) fn trade_workflow_projection_from_storage(
order_id: snapshot.order_id,
agreement: parse_trade_agreement_status("orders.workflow_agreement", snapshot.agreement)?,
revision: snapshot.revision,
- fulfillment: snapshot
- .fulfillment
- .map(|value| parse_trade_fulfillment_status("orders.workflow_fulfillment", value))
- .transpose()?,
- receipt: trade_receipt_projection_from_storage(
- snapshot.receipt_event_id,
- snapshot.receipt_received,
- snapshot.receipt_issue,
- snapshot.receipt_received_at,
- )?,
economics: snapshot.economics,
inventory: parse_trade_inventory_status("orders.workflow_inventory", snapshot.inventory)?,
- payment: parse_trade_payment_display_status("orders.workflow_payment", snapshot.payment)?,
provenance: TradeProvenanceProjection::from_primary_source(parse_trade_workflow_source(
"orders.workflow_provenance_source",
snapshot.provenance_source,
@@ -51,40 +33,6 @@ pub(super) fn trade_workflow_projection_from_storage(
})
}
-fn trade_receipt_projection_from_storage(
- event_id: Option<String>,
- received: Option<i64>,
- issue: Option<String>,
- received_at: Option<i64>,
-) -> Result<Option<TradeReceiptProjection>, AppSqliteError> {
- match (event_id, received, received_at) {
- (None, None, None) => Ok(None),
- (Some(event_id), Some(received), Some(received_at)) => Ok(Some(TradeReceiptProjection {
- event_id,
- received: parse_workflow_receipt_received(received)?,
- issue,
- received_at: u64::try_from(received_at).map_err(|_| {
- AppSqliteError::InvalidProjection {
- reason: "orders.workflow_receipt_received_at must be non-negative",
- }
- })?,
- })),
- _ => Err(AppSqliteError::InvalidProjection {
- reason: "orders.workflow_receipt projection is incomplete",
- }),
- }
-}
-
-fn parse_workflow_receipt_received(value: i64) -> Result<bool, AppSqliteError> {
- match value {
- 0 => Ok(false),
- 1 => Ok(true),
- _ => Err(AppSqliteError::InvalidProjection {
- reason: "orders.workflow_receipt_received must be 0 or 1",
- }),
- }
-}
-
fn parse_trade_agreement_status(
field: &'static str,
value: String,
@@ -94,27 +42,11 @@ fn parse_trade_agreement_status(
"confirmed" => Ok(TradeAgreementStatus::Confirmed),
"declined" => Ok(TradeAgreementStatus::Declined),
"cancelled" => Ok(TradeAgreementStatus::Cancelled),
- "completed" => Ok(TradeAgreementStatus::Completed),
"needs_review" => Ok(TradeAgreementStatus::NeedsReview),
_ => Err(AppSqliteError::DecodeEnum { field, value }),
}
}
-fn parse_trade_fulfillment_status(
- field: &'static str,
- value: String,
-) -> Result<TradeFulfillmentStatus, AppSqliteError> {
- match value.as_str() {
- "confirmed" => Ok(TradeFulfillmentStatus::Confirmed),
- "preparing" => Ok(TradeFulfillmentStatus::Preparing),
- "ready_for_pickup" => Ok(TradeFulfillmentStatus::ReadyForPickup),
- "out_for_delivery" => Ok(TradeFulfillmentStatus::OutForDelivery),
- "delivered" => Ok(TradeFulfillmentStatus::Delivered),
- "cancelled" => Ok(TradeFulfillmentStatus::Cancelled),
- _ => Err(AppSqliteError::DecodeEnum { field, value }),
- }
-}
-
fn parse_trade_inventory_status(
field: &'static str,
value: String,
@@ -128,20 +60,6 @@ fn parse_trade_inventory_status(
}
}
-fn parse_trade_payment_display_status(
- field: &'static str,
- value: String,
-) -> Result<TradePaymentDisplayStatus, AppSqliteError> {
- match value.as_str() {
- "not_recorded" => Ok(TradePaymentDisplayStatus::NotRecorded),
- "pending" => Ok(TradePaymentDisplayStatus::Pending),
- "recorded" => Ok(TradePaymentDisplayStatus::Recorded),
- "settled" => Ok(TradePaymentDisplayStatus::Settled),
- "needs_review" => Ok(TradePaymentDisplayStatus::NeedsReview),
- _ => Err(AppSqliteError::DecodeEnum { field, value }),
- }
-}
-
fn parse_trade_workflow_source(
field: &'static str,
value: String,
@@ -155,42 +73,3 @@ fn parse_trade_workflow_source(
_ => Err(AppSqliteError::DecodeEnum { field, value }),
}
}
-
-#[cfg(test)]
-mod tests {
- use super::parse_trade_payment_display_status;
- use crate::AppSqliteError;
- use radroots_app_view::TradePaymentDisplayStatus;
-
- #[test]
- fn workflow_payment_display_parser_accepts_all_payment_states() {
- for (stored, expected) in [
- ("not_recorded", TradePaymentDisplayStatus::NotRecorded),
- ("pending", TradePaymentDisplayStatus::Pending),
- ("recorded", TradePaymentDisplayStatus::Recorded),
- ("settled", TradePaymentDisplayStatus::Settled),
- ("needs_review", TradePaymentDisplayStatus::NeedsReview),
- ] {
- assert_eq!(
- parse_trade_payment_display_status("orders.workflow_payment", stored.to_owned())
- .expect("workflow payment should parse"),
- expected
- );
- }
- }
-
- #[test]
- fn workflow_payment_display_parser_rejects_unknown_payment_state() {
- let error =
- parse_trade_payment_display_status("orders.workflow_payment", "unknown".to_owned())
- .expect_err("unknown workflow payment should reject");
-
- match error {
- AppSqliteError::DecodeEnum { field, value } => {
- assert_eq!(field, "orders.workflow_payment");
- assert_eq!(value, "unknown");
- }
- other => panic!("expected DecodeEnum error, got {other:?}"),
- }
- }
-}
diff --git a/crates/sync/src/lib.rs b/crates/sync/src/lib.rs
@@ -5,7 +5,6 @@ mod publish;
pub use publish::{
AppFarmProfilePublishPayload, AppListingPublishPayload, AppOrderCancellationPublishPayload,
AppOrderDecisionInventoryCommitment, AppOrderDecisionPayload, AppOrderDecisionPublishPayload,
- AppOrderFulfillmentPublishPayload, AppOrderReceiptOutcome, AppOrderReceiptPublishPayload,
AppOrderRequestItemPayload, AppOrderRequestPublishPayload,
AppOrderRevisionDecisionPublishPayload, AppOrderRevisionProposalPublishPayload,
AppPublishContext, AppPublishPayload, AppPublishPayloadJsonError, AppPublishValidationFailure,
diff --git a/crates/sync/src/publish.rs b/crates/sync/src/publish.rs
@@ -2,13 +2,11 @@ use radroots_app_view::{
FarmId, FarmReadiness, FulfillmentWindowId, OrderId, ProductId, ProductStatus,
};
use radroots_sdk::protocol::order::{
- RadrootsOrderEconomics, RadrootsOrderFulfillmentState, RadrootsOrderItem,
- RadrootsOrderRevisionOutcome,
+ RadrootsOrderEconomics, RadrootsOrderItem, RadrootsOrderRevisionOutcome,
};
use radroots_sdk::{
FARM_PUBLISH_OPERATION_KIND, LISTING_PUBLISH_OPERATION_KIND, ORDER_CANCELLATION_OPERATION_KIND,
- ORDER_DECISION_OPERATION_KIND, ORDER_FULFILLMENT_UPDATE_OPERATION_KIND,
- ORDER_RECEIPT_RECORD_OPERATION_KIND, ORDER_REVISION_DECISION_OPERATION_KIND,
+ ORDER_DECISION_OPERATION_KIND, ORDER_REVISION_DECISION_OPERATION_KIND,
ORDER_REVISION_PROPOSAL_OPERATION_KIND, ORDER_SUBMIT_OPERATION_KIND,
};
use serde::{Deserialize, Serialize};
@@ -26,8 +24,6 @@ pub enum AppPublishWorkKind {
OrderRevisionProposal,
OrderRevisionDecision,
OrderCancellation,
- OrderFulfillment,
- OrderReceipt,
}
impl AppPublishWorkKind {
@@ -40,8 +36,6 @@ impl AppPublishWorkKind {
Self::OrderRevisionProposal => "order_revision_proposal",
Self::OrderRevisionDecision => "order_revision_decision",
Self::OrderCancellation => "order_cancellation",
- Self::OrderFulfillment => "order_fulfillment",
- Self::OrderReceipt => "order_receipt",
}
}
@@ -54,8 +48,6 @@ impl AppPublishWorkKind {
Self::OrderRevisionProposal => ORDER_REVISION_PROPOSAL_OPERATION_KIND,
Self::OrderRevisionDecision => ORDER_REVISION_DECISION_OPERATION_KIND,
Self::OrderCancellation => ORDER_CANCELLATION_OPERATION_KIND,
- Self::OrderFulfillment => ORDER_FULFILLMENT_UPDATE_OPERATION_KIND,
- Self::OrderReceipt => ORDER_RECEIPT_RECORD_OPERATION_KIND,
}
}
}
@@ -220,20 +212,6 @@ pub struct AppOrderRevisionDecisionPublishPayload {
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
-pub struct AppOrderFulfillmentPublishPayload {
- pub context: AppPublishContext,
- pub app_order_id: OrderId,
- pub farm_id: FarmId,
- pub trade_order_id: String,
- pub request_event_id: String,
- pub prev_event_id: String,
- pub listing_addr: String,
- pub buyer_pubkey: String,
- pub seller_pubkey: String,
- pub status: RadrootsOrderFulfillmentState,
-}
-
-#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct AppOrderCancellationPublishPayload {
pub context: AppPublishContext,
pub app_order_id: OrderId,
@@ -248,50 +226,6 @@ pub struct AppOrderCancellationPublishPayload {
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
-pub struct AppOrderReceiptPublishPayload {
- pub context: AppPublishContext,
- pub app_order_id: OrderId,
- pub farm_id: FarmId,
- pub trade_order_id: String,
- pub request_event_id: String,
- pub prev_event_id: String,
- pub listing_addr: String,
- pub buyer_pubkey: String,
- pub seller_pubkey: String,
- pub received: bool,
- pub issue: Option<String>,
- pub received_at: u64,
-}
-
-#[derive(Clone, Debug, Eq, PartialEq)]
-pub enum AppOrderReceiptOutcome {
- Received,
- Issue { issue: String },
-}
-
-impl AppOrderReceiptOutcome {
- pub fn issue(issue: impl Into<String>) -> Option<Self> {
- let issue = issue.into().trim().to_owned();
- if issue.is_empty() {
- None
- } else {
- Some(Self::Issue { issue })
- }
- }
-
- pub const fn received(&self) -> bool {
- matches!(self, Self::Received)
- }
-
- pub fn issue_text(self) -> Option<String> {
- match self {
- Self::Received => None,
- Self::Issue { issue } => Some(issue),
- }
- }
-}
-
-#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(tag = "publish_kind", content = "payload", rename_all = "snake_case")]
pub enum AppPublishPayload {
FarmProfile(AppFarmProfilePublishPayload),
@@ -301,8 +235,6 @@ pub enum AppPublishPayload {
OrderRevisionProposal(AppOrderRevisionProposalPublishPayload),
OrderRevisionDecision(AppOrderRevisionDecisionPublishPayload),
OrderCancellation(AppOrderCancellationPublishPayload),
- OrderFulfillment(AppOrderFulfillmentPublishPayload),
- OrderReceipt(AppOrderReceiptPublishPayload),
}
impl AppPublishPayload {
@@ -315,8 +247,6 @@ impl AppPublishPayload {
Self::OrderRevisionProposal(_) => AppPublishWorkKind::OrderRevisionProposal,
Self::OrderRevisionDecision(_) => AppPublishWorkKind::OrderRevisionDecision,
Self::OrderCancellation(_) => AppPublishWorkKind::OrderCancellation,
- Self::OrderFulfillment(_) => AppPublishWorkKind::OrderFulfillment,
- Self::OrderReceipt(_) => AppPublishWorkKind::OrderReceipt,
}
}
@@ -333,8 +263,6 @@ impl AppPublishPayload {
Self::OrderRevisionProposal(payload) => SyncAggregateRef::Order(payload.app_order_id),
Self::OrderRevisionDecision(payload) => SyncAggregateRef::Order(payload.app_order_id),
Self::OrderCancellation(payload) => SyncAggregateRef::Order(payload.app_order_id),
- Self::OrderFulfillment(payload) => SyncAggregateRef::Order(payload.app_order_id),
- Self::OrderReceipt(payload) => SyncAggregateRef::Order(payload.app_order_id),
}
}
@@ -562,44 +490,6 @@ impl AppPublishPayload {
failures.push(AppPublishValidationFailure::MissingOrderCancellationReason);
}
}
- Self::OrderFulfillment(payload) => {
- validate_lifecycle_order_fields(
- &payload.context,
- payload.trade_order_id.as_str(),
- payload.request_event_id.as_str(),
- payload.prev_event_id.as_str(),
- payload.listing_addr.as_str(),
- payload.buyer_pubkey.as_str(),
- payload.seller_pubkey.as_str(),
- &mut failures,
- );
- if !payload.status.is_publishable_update() {
- failures.push(AppPublishValidationFailure::InvalidOrderFulfillmentStatus);
- }
- }
- Self::OrderReceipt(payload) => {
- validate_lifecycle_order_fields(
- &payload.context,
- payload.trade_order_id.as_str(),
- payload.request_event_id.as_str(),
- payload.prev_event_id.as_str(),
- payload.listing_addr.as_str(),
- payload.buyer_pubkey.as_str(),
- payload.seller_pubkey.as_str(),
- &mut failures,
- );
- if payload.received {
- if payload.issue.is_some() {
- failures.push(AppPublishValidationFailure::UnexpectedOrderReceiptIssue);
- }
- } else if payload
- .issue
- .as_deref()
- .is_none_or(|value| value.trim().is_empty())
- {
- failures.push(AppPublishValidationFailure::MissingOrderReceiptIssue);
- }
- }
}
failures
@@ -689,9 +579,6 @@ pub enum AppPublishValidationFailure {
MissingOrderRevisionReason,
MissingOrderRevisionDecisionReason,
MissingOrderCancellationReason,
- InvalidOrderFulfillmentStatus,
- MissingOrderReceiptIssue,
- UnexpectedOrderReceiptIssue,
}
impl AppPublishValidationFailure {
@@ -731,9 +618,6 @@ impl AppPublishValidationFailure {
Self::MissingOrderRevisionReason => "missing_order_revision_reason",
Self::MissingOrderRevisionDecisionReason => "missing_order_revision_decision_reason",
Self::MissingOrderCancellationReason => "missing_order_cancellation_reason",
- Self::InvalidOrderFulfillmentStatus => "invalid_order_fulfillment_status",
- Self::MissingOrderReceiptIssue => "missing_order_receipt_issue",
- Self::UnexpectedOrderReceiptIssue => "unexpected_order_receipt_issue",
}
}
}
@@ -786,13 +670,11 @@ impl PendingSyncOperation {
mod tests {
use super::{
AppFarmProfilePublishPayload, AppListingPublishPayload, AppOrderCancellationPublishPayload,
- AppOrderDecisionPayload, AppOrderDecisionPublishPayload, AppOrderFulfillmentPublishPayload,
- AppOrderReceiptOutcome, AppOrderReceiptPublishPayload, AppOrderRequestItemPayload,
+ AppOrderDecisionPayload, AppOrderDecisionPublishPayload, AppOrderRequestItemPayload,
AppOrderRequestPublishPayload, AppOrderRevisionDecisionPublishPayload,
AppOrderRevisionProposalPublishPayload, AppPublishContext, AppPublishPayload,
AppPublishValidationFailure, AppPublishWorkKind, FARM_PUBLISH_OPERATION_KIND,
ORDER_CANCELLATION_OPERATION_KIND, ORDER_DECISION_OPERATION_KIND,
- ORDER_FULFILLMENT_UPDATE_OPERATION_KIND, ORDER_RECEIPT_RECORD_OPERATION_KIND,
ORDER_REVISION_DECISION_OPERATION_KIND, ORDER_REVISION_PROPOSAL_OPERATION_KIND,
};
use crate::{
@@ -800,8 +682,7 @@ mod tests {
};
use radroots_app_view::{FarmId, FarmReadiness, OrderId, ProductId, ProductStatus};
use radroots_sdk::protocol::order::{
- RadrootsOrderEconomics, RadrootsOrderFulfillmentState, RadrootsOrderItem,
- RadrootsOrderRevisionOutcome,
+ RadrootsOrderEconomics, RadrootsOrderItem, RadrootsOrderRevisionOutcome,
};
use serde_json::json;
@@ -840,18 +721,7 @@ mod tests {
}
#[test]
- fn order_receipt_outcome_requires_non_empty_issue_text() {
- assert_eq!(AppOrderReceiptOutcome::issue(" "), None);
- assert!(AppOrderReceiptOutcome::Received.received());
-
- let issue = AppOrderReceiptOutcome::issue(" items need review ")
- .expect("issue text should normalize");
- assert!(!issue.received());
- assert_eq!(issue.issue_text().as_deref(), Some("items need review"));
- }
-
- #[test]
- fn publish_work_kinds_keep_payment_and_checkout_surfaces_reserved() {
+ fn publish_work_kinds_are_current_agreement_surface() {
let work_kinds = [
AppPublishWorkKind::FarmProfile,
AppPublishWorkKind::Listing,
@@ -860,31 +730,16 @@ mod tests {
AppPublishWorkKind::OrderRevisionProposal,
AppPublishWorkKind::OrderRevisionDecision,
AppPublishWorkKind::OrderCancellation,
- AppPublishWorkKind::OrderFulfillment,
- AppPublishWorkKind::OrderReceipt,
- ];
- let reserved_publish_tokens = [
- "payment",
- "settlement",
- "checkout",
- "refund",
- "wallet",
- "invoice",
- "processor",
- "provider",
- "escrow",
- "custody",
];
- assert_eq!(work_kinds.len(), 9);
- for work_kind in work_kinds {
- let storage_key = work_kind.storage_key();
- let sdk_operation = work_kind.sdk_operation();
- for reserved_token in reserved_publish_tokens {
- assert!(!storage_key.contains(reserved_token));
- assert!(!sdk_operation.contains(reserved_token));
- }
- }
+ assert_eq!(work_kinds.len(), 7);
+ assert_eq!(work_kinds[0].storage_key(), "farm_profile");
+ assert_eq!(work_kinds[1].storage_key(), "listing");
+ assert_eq!(work_kinds[2].storage_key(), "order_request");
+ assert_eq!(work_kinds[3].storage_key(), "order_decision");
+ assert_eq!(work_kinds[4].storage_key(), "order_revision_proposal");
+ assert_eq!(work_kinds[5].storage_key(), "order_revision_decision");
+ assert_eq!(work_kinds[6].storage_key(), "order_cancellation");
}
#[test]
@@ -1025,7 +880,7 @@ mod tests {
}
#[test]
- fn lifecycle_publish_payloads_report_stable_validation_reason_codes() {
+ fn cancellation_publish_payload_reports_stable_validation_reason_codes() {
let order_id = OrderId::new();
let farm_id = FarmId::new();
let cancellation =
@@ -1041,57 +896,17 @@ mod tests {
seller_pubkey: String::new(),
reason: " ".to_owned(),
});
- let fulfillment = AppPublishPayload::OrderFulfillment(AppOrderFulfillmentPublishPayload {
- context: AppPublishContext::new("acct_local", "seller_order_fulfillment"),
- app_order_id: order_id,
- farm_id,
- trade_order_id: "order-1".to_owned(),
- request_event_id: "request-event-1".to_owned(),
- prev_event_id: "decision-event-1".to_owned(),
- listing_addr: "30402:seller:listing".to_owned(),
- buyer_pubkey: "buyer".to_owned(),
- seller_pubkey: "seller".to_owned(),
- status: RadrootsOrderFulfillmentState::ReadyForPickup,
- });
- let receipt = AppPublishPayload::OrderReceipt(AppOrderReceiptPublishPayload {
- context: AppPublishContext::new("acct_local", "buyer_order_receipt"),
- app_order_id: order_id,
- farm_id,
- trade_order_id: "order-1".to_owned(),
- request_event_id: "request-event-1".to_owned(),
- prev_event_id: "fulfillment-event-1".to_owned(),
- listing_addr: "30402:seller:listing".to_owned(),
- buyer_pubkey: "buyer".to_owned(),
- seller_pubkey: "seller".to_owned(),
- received: true,
- issue: Some("late".to_owned()),
- received_at: 1_785_000_000,
- });
assert_eq!(
cancellation.work_kind().sdk_operation(),
ORDER_CANCELLATION_OPERATION_KIND
);
- assert_eq!(
- fulfillment.work_kind().sdk_operation(),
- ORDER_FULFILLMENT_UPDATE_OPERATION_KIND
- );
- assert_eq!(
- receipt.work_kind().sdk_operation(),
- ORDER_RECEIPT_RECORD_OPERATION_KIND
- );
- assert_eq!(fulfillment.validation_failures(), Vec::new());
let cancellation_reason_codes: Vec<&str> = cancellation
.validation_failures()
.into_iter()
.map(AppPublishValidationFailure::storage_key)
.collect();
- let receipt_reason_codes: Vec<&str> = receipt
- .validation_failures()
- .into_iter()
- .map(AppPublishValidationFailure::storage_key)
- .collect();
assert_eq!(
cancellation_reason_codes,
@@ -1107,33 +922,10 @@ mod tests {
"missing_order_cancellation_reason",
]
);
- assert_eq!(receipt_reason_codes, vec!["unexpected_order_receipt_issue"]);
-
- let invalid_fulfillment_reason_codes: Vec<&str> =
- AppPublishPayload::OrderFulfillment(AppOrderFulfillmentPublishPayload {
- context: AppPublishContext::new("acct_local", "seller_order_fulfillment"),
- app_order_id: order_id,
- farm_id,
- trade_order_id: "order-1".to_owned(),
- request_event_id: "request-event-1".to_owned(),
- prev_event_id: "decision-event-1".to_owned(),
- listing_addr: "30402:seller:listing".to_owned(),
- buyer_pubkey: "buyer".to_owned(),
- seller_pubkey: "seller".to_owned(),
- status: RadrootsOrderFulfillmentState::AcceptedNotFulfilled,
- })
- .validation_failures()
- .into_iter()
- .map(AppPublishValidationFailure::storage_key)
- .collect();
- assert_eq!(
- invalid_fulfillment_reason_codes,
- vec!["invalid_order_fulfillment_status"]
- );
let operation = PendingSyncOperation::from_publish_payload(
- AppPublishPayload::OrderFulfillment(AppOrderFulfillmentPublishPayload {
- context: AppPublishContext::new("acct_local", "seller_order_fulfillment"),
+ AppPublishPayload::OrderCancellation(AppOrderCancellationPublishPayload {
+ context: AppPublishContext::new("acct_local", "buyer_order_cancellation"),
app_order_id: order_id,
farm_id,
trade_order_id: "order-1".to_owned(),
@@ -1142,7 +934,7 @@ mod tests {
listing_addr: "30402:seller:listing".to_owned(),
buyer_pubkey: "buyer".to_owned(),
seller_pubkey: "seller".to_owned(),
- status: RadrootsOrderFulfillmentState::Delivered,
+ reason: "buyer cancelled order".to_owned(),
}),
"2026-04-20T18:00:00Z",
)
@@ -1153,8 +945,8 @@ mod tests {
assert_eq!(operation.operation, SyncOperationKind::Upsert);
assert_eq!(
operation.publish_payload().expect("payload should parse"),
- AppPublishPayload::OrderFulfillment(AppOrderFulfillmentPublishPayload {
- context: AppPublishContext::new("acct_local", "seller_order_fulfillment"),
+ AppPublishPayload::OrderCancellation(AppOrderCancellationPublishPayload {
+ context: AppPublishContext::new("acct_local", "buyer_order_cancellation"),
app_order_id: order_id,
farm_id,
trade_order_id: "order-1".to_owned(),
@@ -1163,7 +955,7 @@ mod tests {
listing_addr: "30402:seller:listing".to_owned(),
buyer_pubkey: "buyer".to_owned(),
seller_pubkey: "seller".to_owned(),
- status: RadrootsOrderFulfillmentState::Delivered,
+ reason: "buyer cancelled order".to_owned(),
})
);
}
diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs
@@ -341,7 +341,6 @@ pub enum OrderStatus {
Packed,
Completed,
Declined,
- Refunded,
NeedsReview,
}
@@ -353,7 +352,6 @@ impl OrderStatus {
Self::Packed => "packed",
Self::Completed => "completed",
Self::Declined => "declined",
- Self::Refunded => "refunded",
Self::NeedsReview => "needs_review",
}
}
@@ -367,7 +365,6 @@ pub enum BuyerOrderStatus {
Ready,
Completed,
Declined,
- Refunded,
NeedsReview,
}
@@ -379,7 +376,6 @@ impl BuyerOrderStatus {
Self::Ready => "ready",
Self::Completed => "completed",
Self::Declined => "declined",
- Self::Refunded => "refunded",
Self::NeedsReview => "needs_review",
}
}
@@ -393,7 +389,6 @@ impl From<OrderStatus> for BuyerOrderStatus {
OrderStatus::Packed => Self::Ready,
OrderStatus::Completed => Self::Completed,
OrderStatus::Declined => Self::Declined,
- OrderStatus::Refunded => Self::Refunded,
OrderStatus::NeedsReview => Self::NeedsReview,
}
}
@@ -695,10 +690,7 @@ impl PackDayOutputOrderState {
OrderStatus::NeedsAction => Some(Self::NeedsAction),
OrderStatus::Scheduled => Some(Self::Scheduled),
OrderStatus::Packed => Some(Self::Packed),
- OrderStatus::Completed
- | OrderStatus::Declined
- | OrderStatus::Refunded
- | OrderStatus::NeedsReview => None,
+ OrderStatus::Completed | OrderStatus::Declined | OrderStatus::NeedsReview => None,
}
}
}
@@ -845,7 +837,6 @@ pub enum ReminderKind {
FulfillmentWindow,
OrderAction,
MissedPickupRecovery,
- RefundRecovery,
SyncImpact,
}
@@ -855,7 +846,6 @@ impl ReminderKind {
Self::FulfillmentWindow => "fulfillment_window",
Self::OrderAction => "order_action",
Self::MissedPickupRecovery => "missed_pickup_recovery",
- Self::RefundRecovery => "refund_recovery",
Self::SyncImpact => "sync_impact",
}
}
@@ -905,14 +895,12 @@ impl ReminderDeliveryState {
#[serde(rename_all = "snake_case")]
pub enum RecoveryKind {
MissedPickup,
- RefundFollowUp,
}
impl RecoveryKind {
pub const fn storage_key(self) -> &'static str {
match self {
Self::MissedPickup => "missed_pickup",
- Self::RefundFollowUp => "refund_follow_up",
}
}
}
diff --git a/crates/view/src/lib.rs b/crates/view/src/lib.rs
@@ -3,11 +3,8 @@
pub use radroots_app_types::*;
use radroots_core::RadrootsCoreMoney;
-use radroots_events::order::{RadrootsOrderEconomics, RadrootsOrderFulfillmentState};
-use radroots_trade::order::{
- RadrootsOrderPaymentProjection, RadrootsOrderPaymentState, RadrootsOrderProjection,
- RadrootsOrderSettlementState, RadrootsOrderStatus,
-};
+use radroots_events::order::RadrootsOrderEconomics;
+use radroots_trade::order::{RadrootsOrderProjection, RadrootsOrderStatus};
use radroots_trade::validation_receipt::{
RadrootsValidationReceiptProofSystem, RadrootsValidationReceiptResult,
RadrootsValidationReceiptType,
@@ -1079,7 +1076,6 @@ pub enum TradeAgreementStatus {
Confirmed,
Declined,
Cancelled,
- Completed,
NeedsReview,
}
@@ -1090,7 +1086,6 @@ impl TradeAgreementStatus {
Self::Confirmed => "confirmed",
Self::Declined => "declined",
Self::Cancelled => "cancelled",
- Self::Completed => "completed",
Self::NeedsReview => "needs_review",
}
}
@@ -1101,7 +1096,6 @@ impl TradeAgreementStatus {
Self::Confirmed => "messages.trade.workflow.agreement.confirmed",
Self::Declined => "messages.trade.workflow.agreement.declined",
Self::Cancelled => "messages.trade.workflow.agreement.cancelled",
- Self::Completed => "messages.trade.workflow.agreement.completed",
Self::NeedsReview => "messages.trade.workflow.agreement.needs_review",
}
}
@@ -1113,8 +1107,7 @@ impl TradeAgreementStatus {
RadrootsOrderStatus::Accepted => Self::Confirmed,
RadrootsOrderStatus::Declined => Self::Declined,
RadrootsOrderStatus::Cancelled => Self::Cancelled,
- RadrootsOrderStatus::Completed => Self::Completed,
- RadrootsOrderStatus::Disputed | RadrootsOrderStatus::Invalid => Self::NeedsReview,
+ RadrootsOrderStatus::Invalid => Self::NeedsReview,
}
}
}
@@ -1188,59 +1181,6 @@ impl TradeRevisionStatus {
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
-pub enum TradeFulfillmentStatus {
- #[default]
- Confirmed,
- Preparing,
- ReadyForPickup,
- OutForDelivery,
- Delivered,
- Cancelled,
-}
-
-impl TradeFulfillmentStatus {
- pub const fn storage_key(self) -> &'static str {
- match self {
- Self::Confirmed => "confirmed",
- Self::Preparing => "preparing",
- Self::ReadyForPickup => "ready_for_pickup",
- Self::OutForDelivery => "out_for_delivery",
- Self::Delivered => "delivered",
- Self::Cancelled => "cancelled",
- }
- }
-
- pub const fn label_key_id(self) -> &'static str {
- match self {
- Self::Confirmed => "messages.trade.workflow.fulfillment.confirmed",
- Self::Preparing => "messages.trade.workflow.fulfillment.preparing",
- Self::ReadyForPickup => "messages.trade.workflow.fulfillment.ready_for_pickup",
- Self::OutForDelivery => "messages.trade.workflow.fulfillment.out_for_delivery",
- Self::Delivered => "messages.trade.workflow.fulfillment.delivered",
- Self::Cancelled => "messages.trade.workflow.fulfillment.cancelled",
- }
- }
-
- pub const fn from_active_fulfillment_status(status: &RadrootsOrderFulfillmentState) -> Self {
- match status {
- RadrootsOrderFulfillmentState::AcceptedNotFulfilled => Self::Confirmed,
- RadrootsOrderFulfillmentState::Preparing => Self::Preparing,
- RadrootsOrderFulfillmentState::ReadyForPickup => Self::ReadyForPickup,
- RadrootsOrderFulfillmentState::OutForDelivery => Self::OutForDelivery,
- RadrootsOrderFulfillmentState::Delivered => Self::Delivered,
- RadrootsOrderFulfillmentState::SellerCancelled => Self::Cancelled,
- }
- }
-}
-
-impl From<&RadrootsOrderFulfillmentState> for TradeFulfillmentStatus {
- fn from(status: &RadrootsOrderFulfillmentState) -> Self {
- Self::from_active_fulfillment_status(status)
- }
-}
-
-#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
-#[serde(rename_all = "snake_case")]
pub enum TradeInventoryStatus {
Available,
Reserved,
@@ -1269,95 +1209,11 @@ impl TradeInventoryStatus {
}
pub fn from_active_order_projection(projection: &RadrootsOrderProjection) -> Self {
- match (&projection.status, projection.fulfillment_status.as_ref()) {
- (RadrootsOrderStatus::Requested, _) => Self::NeedsReview,
- (
- RadrootsOrderStatus::Accepted,
- Some(RadrootsOrderFulfillmentState::SellerCancelled),
- ) => Self::Available,
- (RadrootsOrderStatus::Accepted, _) => Self::Reserved,
- (RadrootsOrderStatus::Declined | RadrootsOrderStatus::Cancelled, _) => Self::Available,
- (RadrootsOrderStatus::Completed, _) => Self::Reserved,
- (
- RadrootsOrderStatus::Missing
- | RadrootsOrderStatus::Disputed
- | RadrootsOrderStatus::Invalid,
- _,
- ) => Self::NeedsReview,
- }
- }
-}
-
-#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
-#[serde(rename_all = "snake_case")]
-pub enum TradePaymentDisplayStatus {
- #[default]
- NotRecorded,
- Pending,
- Recorded,
- Settled,
- NeedsReview,
-}
-
-impl TradePaymentDisplayStatus {
- pub const fn storage_key(self) -> &'static str {
- match self {
- Self::NotRecorded => "not_recorded",
- Self::Pending => "pending",
- Self::Recorded => "recorded",
- Self::Settled => "settled",
- Self::NeedsReview => "needs_review",
- }
- }
-
- pub const fn label_key_id(self) -> &'static str {
- match self {
- Self::NotRecorded => "messages.trade.workflow.payment.not_recorded",
- Self::Pending => "messages.trade.workflow.payment.pending",
- Self::Recorded => "messages.trade.workflow.payment.recorded",
- Self::Settled => "messages.trade.workflow.payment.settled",
- Self::NeedsReview => "messages.trade.workflow.payment.needs_review",
- }
- }
-
- pub const fn allows_payment_action(self) -> bool {
- false
- }
-
- pub fn from_active_payment_state(status: &RadrootsOrderPaymentState) -> Self {
- match status {
- RadrootsOrderPaymentState::NotRecorded => Self::NotRecorded,
- RadrootsOrderPaymentState::Recorded => Self::Recorded,
- RadrootsOrderPaymentState::Settled => Self::Settled,
- RadrootsOrderPaymentState::Rejected | RadrootsOrderPaymentState::Invalid => {
- Self::NeedsReview
- }
- }
- }
-
- pub fn from_active_payment_projection(payment: &RadrootsOrderPaymentProjection) -> Self {
- match (&payment.state, &payment.settlement_state) {
- (RadrootsOrderPaymentState::NotRecorded, RadrootsOrderSettlementState::NotRequired) => {
- Self::NotRecorded
- }
- (RadrootsOrderPaymentState::NotRecorded, _) => Self::NeedsReview,
- (RadrootsOrderPaymentState::Recorded, RadrootsOrderSettlementState::Pending) => {
- Self::Pending
- }
- (RadrootsOrderPaymentState::Recorded, RadrootsOrderSettlementState::NotRequired) => {
- Self::Recorded
- }
- (RadrootsOrderPaymentState::Recorded, RadrootsOrderSettlementState::Accepted) => {
- Self::Settled
- }
- (
- RadrootsOrderPaymentState::Recorded,
- RadrootsOrderSettlementState::Rejected | RadrootsOrderSettlementState::Invalid,
- ) => Self::NeedsReview,
- (RadrootsOrderPaymentState::Settled, _) => Self::Settled,
- (RadrootsOrderPaymentState::Rejected | RadrootsOrderPaymentState::Invalid, _) => {
- Self::NeedsReview
- }
+ match projection.status {
+ RadrootsOrderStatus::Requested => Self::NeedsReview,
+ RadrootsOrderStatus::Accepted => Self::Reserved,
+ RadrootsOrderStatus::Declined | RadrootsOrderStatus::Cancelled => Self::Available,
+ RadrootsOrderStatus::Missing | RadrootsOrderStatus::Invalid => Self::NeedsReview,
}
}
}
@@ -1463,25 +1319,6 @@ impl Default for TradeProvenanceProjection {
}
}
-#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
-pub struct TradeReceiptProjection {
- pub event_id: String,
- pub received: bool,
- pub issue: Option<String>,
- pub received_at: u64,
-}
-
-impl TradeReceiptProjection {
- pub fn from_active_order_projection(projection: &RadrootsOrderProjection) -> Option<Self> {
- Some(Self {
- event_id: projection.receipt_event_id.as_ref()?.to_string(),
- received: projection.receipt_received?,
- issue: projection.receipt_issue.clone(),
- received_at: projection.receipt_received_at?,
- })
- }
-}
-
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum TradeValidationReceiptResult {
@@ -1615,11 +1452,8 @@ pub struct TradeWorkflowProjection {
pub order_id: OrderId,
pub agreement: TradeAgreementStatus,
pub revision: TradeRevisionStatus,
- pub fulfillment: Option<TradeFulfillmentStatus>,
- pub receipt: Option<TradeReceiptProjection>,
pub economics: TradeEconomicsProjection,
pub inventory: TradeInventoryStatus,
- pub payment: TradePaymentDisplayStatus,
pub provenance: TradeProvenanceProjection,
}
@@ -1629,11 +1463,8 @@ impl TradeWorkflowProjection {
order_id,
agreement,
revision: TradeRevisionStatus::None,
- fulfillment: None,
- receipt: None,
economics: TradeEconomicsProjection::default(),
inventory: TradeInventoryStatus::NeedsReview,
- payment: TradePaymentDisplayStatus::NotRecorded,
provenance: TradeProvenanceProjection::default(),
}
}
@@ -1649,19 +1480,12 @@ impl TradeWorkflowProjection {
TradeAgreementStatus::from_active_order_status(&projection.status),
);
workflow.revision = revision;
- workflow.fulfillment = projection
- .fulfillment_status
- .as_ref()
- .map(TradeFulfillmentStatus::from_active_fulfillment_status);
- workflow.receipt = TradeReceiptProjection::from_active_order_projection(projection);
workflow.economics = projection
.economics
.as_ref()
.map(TradeEconomicsProjection::from_trade_order_economics)
.unwrap_or_default();
workflow.inventory = TradeInventoryStatus::from_active_order_projection(projection);
- workflow.payment =
- TradePaymentDisplayStatus::from_active_payment_projection(&projection.payment);
workflow.provenance = provenance
.with_last_event_id(projection.last_event_id.as_ref().map(ToString::to_string));
workflow
@@ -1672,34 +1496,26 @@ impl TradeWorkflowProjection {
OrderStatus::NeedsAction => Self::new(order_id, TradeAgreementStatus::Ordered),
OrderStatus::Scheduled => Self::new(order_id, TradeAgreementStatus::Confirmed),
OrderStatus::Packed => Self::new(order_id, TradeAgreementStatus::Confirmed),
- OrderStatus::Completed => Self::new(order_id, TradeAgreementStatus::Completed),
+ OrderStatus::Completed => Self::new(order_id, TradeAgreementStatus::Confirmed),
OrderStatus::Declined => Self::new(order_id, TradeAgreementStatus::Declined),
- OrderStatus::Refunded | OrderStatus::NeedsReview => {
- Self::new(order_id, TradeAgreementStatus::NeedsReview)
- }
+ OrderStatus::NeedsReview => Self::new(order_id, TradeAgreementStatus::NeedsReview),
};
match status {
OrderStatus::NeedsAction => {}
OrderStatus::Scheduled => {
- projection.fulfillment = Some(TradeFulfillmentStatus::Confirmed);
projection.inventory = TradeInventoryStatus::Reserved;
}
OrderStatus::Packed => {
- projection.fulfillment = Some(TradeFulfillmentStatus::ReadyForPickup);
projection.inventory = TradeInventoryStatus::Reserved;
}
OrderStatus::Completed => {
- projection.fulfillment = Some(TradeFulfillmentStatus::Delivered);
projection.inventory = TradeInventoryStatus::Reserved;
}
OrderStatus::Declined => {
- projection.fulfillment = Some(TradeFulfillmentStatus::Cancelled);
projection.inventory = TradeInventoryStatus::Available;
}
- OrderStatus::Refunded | OrderStatus::NeedsReview => {
- projection.payment = TradePaymentDisplayStatus::NeedsReview;
- }
+ OrderStatus::NeedsReview => {}
}
projection
@@ -1710,34 +1526,26 @@ impl TradeWorkflowProjection {
BuyerOrderStatus::Placed => Self::new(order_id, TradeAgreementStatus::Ordered),
BuyerOrderStatus::Scheduled => Self::new(order_id, TradeAgreementStatus::Confirmed),
BuyerOrderStatus::Ready => Self::new(order_id, TradeAgreementStatus::Confirmed),
- BuyerOrderStatus::Completed => Self::new(order_id, TradeAgreementStatus::Completed),
+ BuyerOrderStatus::Completed => Self::new(order_id, TradeAgreementStatus::Confirmed),
BuyerOrderStatus::Declined => Self::new(order_id, TradeAgreementStatus::Declined),
- BuyerOrderStatus::Refunded | BuyerOrderStatus::NeedsReview => {
- Self::new(order_id, TradeAgreementStatus::NeedsReview)
- }
+ BuyerOrderStatus::NeedsReview => Self::new(order_id, TradeAgreementStatus::NeedsReview),
};
match status {
BuyerOrderStatus::Placed => {}
BuyerOrderStatus::Scheduled => {
- projection.fulfillment = Some(TradeFulfillmentStatus::Confirmed);
projection.inventory = TradeInventoryStatus::Reserved;
}
BuyerOrderStatus::Ready => {
- projection.fulfillment = Some(TradeFulfillmentStatus::ReadyForPickup);
projection.inventory = TradeInventoryStatus::Reserved;
}
BuyerOrderStatus::Completed => {
- projection.fulfillment = Some(TradeFulfillmentStatus::Delivered);
projection.inventory = TradeInventoryStatus::Reserved;
}
BuyerOrderStatus::Declined => {
- projection.fulfillment = Some(TradeFulfillmentStatus::Cancelled);
projection.inventory = TradeInventoryStatus::Available;
}
- BuyerOrderStatus::Refunded | BuyerOrderStatus::NeedsReview => {
- projection.payment = TradePaymentDisplayStatus::NeedsReview;
- }
+ BuyerOrderStatus::NeedsReview => {}
}
projection
@@ -1748,56 +1556,23 @@ impl TradeWorkflowProjection {
self
}
- pub fn with_payment(mut self, payment: TradePaymentDisplayStatus) -> Self {
- self.payment = payment;
- self
- }
-
pub fn with_revision(mut self, revision: TradeRevisionStatus) -> Self {
self.revision = revision;
self
}
-
- pub fn with_economics_and_payment(
- self,
- economics: TradeEconomicsProjection,
- payment: TradePaymentDisplayStatus,
- ) -> Self {
- self.with_economics(economics).with_payment(payment)
- }
}
pub fn order_status_from_active_order_projection(
projection: &RadrootsOrderProjection,
) -> Option<OrderStatus> {
- match (&projection.status, projection.fulfillment_status.as_ref()) {
- (RadrootsOrderStatus::Missing, _) => None,
- (RadrootsOrderStatus::Requested, _) => Some(OrderStatus::NeedsAction),
- (
- RadrootsOrderStatus::Accepted,
- Some(
- RadrootsOrderFulfillmentState::ReadyForPickup
- | RadrootsOrderFulfillmentState::OutForDelivery
- | RadrootsOrderFulfillmentState::Delivered,
- ),
- ) => Some(OrderStatus::Packed),
- (RadrootsOrderStatus::Accepted, Some(RadrootsOrderFulfillmentState::SellerCancelled)) => {
- Some(OrderStatus::Declined)
- }
- (
- RadrootsOrderStatus::Accepted,
- Some(
- RadrootsOrderFulfillmentState::Preparing
- | RadrootsOrderFulfillmentState::AcceptedNotFulfilled,
- )
- | None,
- ) => Some(OrderStatus::Scheduled),
- (RadrootsOrderStatus::Declined | RadrootsOrderStatus::Cancelled, _) => {
+ match projection.status {
+ RadrootsOrderStatus::Missing => None,
+ RadrootsOrderStatus::Requested => Some(OrderStatus::NeedsAction),
+ RadrootsOrderStatus::Accepted => Some(OrderStatus::Scheduled),
+ RadrootsOrderStatus::Declined | RadrootsOrderStatus::Cancelled => {
Some(OrderStatus::Declined)
}
- (RadrootsOrderStatus::Completed, _) => Some(OrderStatus::Completed),
- (RadrootsOrderStatus::Disputed, _) => Some(OrderStatus::NeedsReview),
- (RadrootsOrderStatus::Invalid, _) => Some(OrderStatus::NeedsAction),
+ RadrootsOrderStatus::Invalid => Some(OrderStatus::NeedsAction),
}
}
@@ -1810,7 +1585,6 @@ pub enum OrdersFilter {
Scheduled,
Packed,
Completed,
- Refunded,
}
impl OrdersFilter {
@@ -1821,7 +1595,6 @@ impl OrdersFilter {
Self::Scheduled => "scheduled",
Self::Packed => "packed",
Self::Completed => "completed",
- Self::Refunded => "refunded",
}
}
}
@@ -1834,87 +1607,14 @@ pub struct OrdersScreenQueryState {
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
-pub enum OrderFulfillmentAction {
- Preparing,
- ReadyForPickup,
- OutForDelivery,
- Delivered,
- SellerCancelled,
-}
-
-impl OrderFulfillmentAction {
- pub const ALL: &'static [Self] = &[
- Self::Preparing,
- Self::ReadyForPickup,
- Self::OutForDelivery,
- Self::Delivered,
- Self::SellerCancelled,
- ];
-
- pub const fn storage_key(self) -> &'static str {
- match self {
- Self::Preparing => "publish_preparing",
- Self::ReadyForPickup => "publish_ready_for_pickup",
- Self::OutForDelivery => "publish_out_for_delivery",
- Self::Delivered => "publish_delivered",
- Self::SellerCancelled => "publish_seller_cancelled",
- }
- }
-
- pub const fn fulfillment_status(self) -> RadrootsOrderFulfillmentState {
- match self {
- Self::Preparing => RadrootsOrderFulfillmentState::Preparing,
- Self::ReadyForPickup => RadrootsOrderFulfillmentState::ReadyForPickup,
- Self::OutForDelivery => RadrootsOrderFulfillmentState::OutForDelivery,
- Self::Delivered => RadrootsOrderFulfillmentState::Delivered,
- Self::SellerCancelled => RadrootsOrderFulfillmentState::SellerCancelled,
- }
- }
-}
-
-#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
-#[serde(rename_all = "snake_case")]
pub enum OrderPrimaryAction {
Review,
- PublishPreparing,
- PublishReadyForPickup,
- PublishOutForDelivery,
- PublishDelivered,
- PublishSellerCancelled,
}
impl OrderPrimaryAction {
pub const fn storage_key(self) -> &'static str {
match self {
Self::Review => "review",
- Self::PublishPreparing => "publish_preparing",
- Self::PublishReadyForPickup => "publish_ready_for_pickup",
- Self::PublishOutForDelivery => "publish_out_for_delivery",
- Self::PublishDelivered => "publish_delivered",
- Self::PublishSellerCancelled => "publish_seller_cancelled",
- }
- }
-
- pub const fn fulfillment_action(self) -> Option<OrderFulfillmentAction> {
- match self {
- Self::Review => None,
- Self::PublishPreparing => Some(OrderFulfillmentAction::Preparing),
- Self::PublishReadyForPickup => Some(OrderFulfillmentAction::ReadyForPickup),
- Self::PublishOutForDelivery => Some(OrderFulfillmentAction::OutForDelivery),
- Self::PublishDelivered => Some(OrderFulfillmentAction::Delivered),
- Self::PublishSellerCancelled => Some(OrderFulfillmentAction::SellerCancelled),
- }
- }
-}
-
-impl From<OrderFulfillmentAction> for OrderPrimaryAction {
- fn from(action: OrderFulfillmentAction) -> Self {
- match action {
- OrderFulfillmentAction::Preparing => Self::PublishPreparing,
- OrderFulfillmentAction::ReadyForPickup => Self::PublishReadyForPickup,
- OrderFulfillmentAction::OutForDelivery => Self::PublishOutForDelivery,
- OrderFulfillmentAction::Delivered => Self::PublishDelivered,
- OrderFulfillmentAction::SellerCancelled => Self::PublishSellerCancelled,
}
}
}
@@ -1945,7 +1645,6 @@ pub struct OrdersListRow {
pub status: OrderStatus,
pub workflow: TradeWorkflowProjection,
pub primary_action: Option<OrderPrimaryAction>,
- pub fulfillment_actions: Vec<OrderFulfillmentAction>,
}
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
@@ -1980,11 +1679,9 @@ pub struct OrderDetailProjection {
pub pickup_location_label: Option<String>,
pub items: Vec<OrderDetailItemRow>,
pub economics: TradeEconomicsProjection,
- pub payment: TradePaymentDisplayStatus,
pub workflow: TradeWorkflowProjection,
pub validation_receipts: Vec<TradeValidationReceiptProjection>,
pub primary_action: Option<OrderPrimaryAction>,
- pub fulfillment_actions: Vec<OrderFulfillmentAction>,
pub recoveries: Vec<OrderRecoveryProjection>,
}
@@ -2021,7 +1718,6 @@ pub struct BuyerOrderDetailProjection {
pub status: BuyerOrderStatus,
pub items: Vec<OrderDetailItemRow>,
pub economics: TradeEconomicsProjection,
- pub payment: TradePaymentDisplayStatus,
pub workflow: TradeWorkflowProjection,
pub validation_receipts: Vec<TradeValidationReceiptProjection>,
pub order_note: Option<String>,
@@ -2441,13 +2137,9 @@ mod tests {
RadrootsOrderQuoteId, RadrootsPublicKey,
};
use radroots_events::order::{
- RadrootsOrderEconomicItem, RadrootsOrderEconomics, RadrootsOrderFulfillmentState,
- RadrootsOrderPricingBasis,
- };
- use radroots_trade::order::{
- RadrootsOrderPaymentProjection, RadrootsOrderPaymentState, RadrootsOrderProjection,
- RadrootsOrderSettlementState, RadrootsOrderStatus,
+ RadrootsOrderEconomicItem, RadrootsOrderEconomics, RadrootsOrderPricingBasis,
};
+ use radroots_trade::order::{RadrootsOrderProjection, RadrootsOrderStatus};
use radroots_trade::validation_receipt::{
RadrootsValidationReceiptProofSystem, RadrootsValidationReceiptResult,
RadrootsValidationReceiptType,
@@ -2465,12 +2157,12 @@ mod tests {
FarmSetupProjection, FarmSetupReadiness, FarmSetupSection, FarmTimingConflict,
FarmTimingConflictKind, FarmerActivationProjection, FarmerSection, FulfillmentWindowId,
IdentityBlockedReason, IdentityReadiness, LoggedOutStartupPhase,
- LoggedOutStartupProjection, OrderDetailItemRow, OrderDetailProjection,
- OrderFulfillmentAction, OrderId, OrderListRow, OrderPrimaryAction, OrderRecoveryProjection,
- OrderStatus, OrdersFilter, OrdersListProjection, OrdersListRow, OrdersListSummary,
- OrdersScreenQueryState, PackDayBatchPrintArtifact, PackDayBatchPrintFailureKind,
- PackDayBatchPrintStatus, PackDayExportArtifact, PackDayExportArtifactKind,
- PackDayExportBundle, PackDayExportInstanceId, PackDayExportStatus, PackDayHostHandoffKind,
+ LoggedOutStartupProjection, OrderDetailItemRow, OrderDetailProjection, OrderId,
+ OrderListRow, OrderPrimaryAction, OrderRecoveryProjection, OrderStatus, OrdersFilter,
+ OrdersListProjection, OrdersListRow, OrdersListSummary, OrdersScreenQueryState,
+ PackDayBatchPrintArtifact, PackDayBatchPrintFailureKind, PackDayBatchPrintStatus,
+ PackDayExportArtifact, PackDayExportArtifactKind, PackDayExportBundle,
+ PackDayExportInstanceId, PackDayExportStatus, PackDayHostHandoffKind,
PackDayHostHandoffStatus, PackDayOutputCustomerOrder, PackDayOutputOrderState,
PackDayOutputPackListEntry, PackDayOutputProductTotal, PackDayOutputQuantity,
PackDayOutputSource, PackDayOutputWindow, PackDayPackListRow, PackDayPrintFailureKind,
@@ -2488,11 +2180,10 @@ mod tests {
SelectedAccountProjection, SelectedSurfaceProjection, SettingsPreference, SettingsSection,
ShellSection, StartupSignerEntryProjection, StartupSignerSource, StartupSignerSourceKind,
TodayAgendaProjection, TodaySetupTask, TodaySetupTaskKind, TodaySummary,
- TradeAgreementStatus, TradeEconomicsProjection, TradeFulfillmentStatus,
- TradeInventoryStatus, TradePaymentDisplayStatus, TradeProvenanceProjection,
- TradeRevisionStatus, TradeValidationReceiptProofSystem, TradeValidationReceiptResult,
- TradeValidationReceiptType, TradeWorkflowProjection, TradeWorkflowSource,
- order_status_from_active_order_projection,
+ TradeAgreementStatus, TradeEconomicsProjection, TradeInventoryStatus,
+ TradeProvenanceProjection, TradeRevisionStatus, TradeValidationReceiptProofSystem,
+ TradeValidationReceiptResult, TradeValidationReceiptType, TradeWorkflowProjection,
+ TradeWorkflowSource, order_status_from_active_order_projection,
};
use std::{collections::BTreeSet, str::FromStr};
use uuid::Uuid;
@@ -3067,14 +2758,12 @@ mod tests {
assert_eq!(OrderStatus::Packed.storage_key(), "packed");
assert_eq!(OrderStatus::Completed.storage_key(), "completed");
assert_eq!(OrderStatus::Declined.storage_key(), "declined");
- assert_eq!(OrderStatus::Refunded.storage_key(), "refunded");
assert_eq!(OrderStatus::NeedsReview.storage_key(), "needs_review");
assert_eq!(BuyerOrderStatus::Placed.storage_key(), "placed");
assert_eq!(BuyerOrderStatus::Scheduled.storage_key(), "scheduled");
assert_eq!(BuyerOrderStatus::Ready.storage_key(), "ready");
assert_eq!(BuyerOrderStatus::Completed.storage_key(), "completed");
assert_eq!(BuyerOrderStatus::Declined.storage_key(), "declined");
- assert_eq!(BuyerOrderStatus::Refunded.storage_key(), "refunded");
assert_eq!(BuyerOrderStatus::NeedsReview.storage_key(), "needs_review");
assert_eq!(
BuyerOrderStatus::from(OrderStatus::NeedsAction),
@@ -3099,45 +2788,8 @@ mod tests {
assert_eq!(OrdersFilter::Scheduled.storage_key(), "scheduled");
assert_eq!(OrdersFilter::Packed.storage_key(), "packed");
assert_eq!(OrdersFilter::Completed.storage_key(), "completed");
- assert_eq!(OrdersFilter::Refunded.storage_key(), "refunded");
assert_eq!(OrderPrimaryAction::Review.storage_key(), "review");
- assert_eq!(
- OrderFulfillmentAction::Preparing.storage_key(),
- "publish_preparing"
- );
- assert_eq!(
- OrderFulfillmentAction::ReadyForPickup.storage_key(),
- "publish_ready_for_pickup"
- );
- assert_eq!(
- OrderFulfillmentAction::OutForDelivery.storage_key(),
- "publish_out_for_delivery"
- );
- assert_eq!(
- OrderFulfillmentAction::Delivered.storage_key(),
- "publish_delivered"
- );
- assert_eq!(
- OrderFulfillmentAction::SellerCancelled.storage_key(),
- "publish_seller_cancelled"
- );
- assert_eq!(
- OrderFulfillmentAction::Preparing.fulfillment_status(),
- RadrootsOrderFulfillmentState::Preparing
- );
- assert_eq!(
- OrderPrimaryAction::PublishReadyForPickup.storage_key(),
- "publish_ready_for_pickup"
- );
- assert_eq!(
- OrderPrimaryAction::PublishOutForDelivery.storage_key(),
- "publish_out_for_delivery"
- );
- assert_eq!(
- OrderPrimaryAction::PublishDelivered.storage_key(),
- "publish_delivered"
- );
}
fn test_decimal(raw: &str) -> RadrootsCoreDecimal {
@@ -3196,26 +2848,7 @@ mod tests {
}
}
- fn test_payment_projection(state: RadrootsOrderPaymentState) -> RadrootsOrderPaymentProjection {
- let mut projection = RadrootsOrderPaymentProjection::not_recorded();
- projection.payment_event_id = (!matches!(&state, RadrootsOrderPaymentState::NotRecorded))
- .then(|| {
- test_event_id("4444444444444444444444444444444444444444444444444444444444444444")
- });
- projection.settlement_state = match &state {
- RadrootsOrderPaymentState::Settled => RadrootsOrderSettlementState::Accepted,
- RadrootsOrderPaymentState::Invalid => RadrootsOrderSettlementState::Invalid,
- _ => RadrootsOrderSettlementState::NotRequired,
- };
- projection.state = state;
- projection
- }
-
- fn test_active_order_projection(
- status: RadrootsOrderStatus,
- fulfillment_status: Option<RadrootsOrderFulfillmentState>,
- payment_state: RadrootsOrderPaymentState,
- ) -> RadrootsOrderProjection {
+ fn test_active_order_projection(status: RadrootsOrderStatus) -> RadrootsOrderProjection {
RadrootsOrderProjection {
order_id: test_order_id("ord_AAAAAAAAAAAAAAAAAAAAAg"),
status,
@@ -3225,17 +2858,8 @@ mod tests {
decision_event_id: Some(test_event_id(
"2222222222222222222222222222222222222222222222222222222222222222",
)),
- fulfillment_event_id: fulfillment_status.as_ref().map(|_| {
- test_event_id("3333333333333333333333333333333333333333333333333333333333333333")
- }),
- fulfillment_status,
cancellation_event_id: None,
- receipt_event_id: None,
- receipt_received: None,
- receipt_issue: None,
- receipt_received_at: None,
lifecycle_terminal: false,
- payment: test_payment_projection(payment_state),
economics: Some(test_trade_economics()),
agreement_event_id: Some(test_event_id(
"2222222222222222222222222222222222222222222222222222222222222222",
@@ -3268,38 +2892,10 @@ mod tests {
TradeAgreementStatus::Confirmed
);
assert_eq!(
- TradeAgreementStatus::from_active_order_status(&RadrootsOrderStatus::Disputed),
- TradeAgreementStatus::NeedsReview
- );
- assert_eq!(
TradeAgreementStatus::from_active_order_status(&RadrootsOrderStatus::Invalid),
TradeAgreementStatus::NeedsReview
);
assert_eq!(
- TradeFulfillmentStatus::from_active_fulfillment_status(
- &RadrootsOrderFulfillmentState::AcceptedNotFulfilled
- ),
- TradeFulfillmentStatus::Confirmed
- );
- assert_eq!(
- TradeFulfillmentStatus::from_active_fulfillment_status(
- &RadrootsOrderFulfillmentState::SellerCancelled
- ),
- TradeFulfillmentStatus::Cancelled
- );
- assert_eq!(
- TradePaymentDisplayStatus::from_active_payment_state(
- &RadrootsOrderPaymentState::Settled
- ),
- TradePaymentDisplayStatus::Settled
- );
- assert_eq!(
- TradePaymentDisplayStatus::from_active_payment_state(
- &RadrootsOrderPaymentState::Rejected
- ),
- TradePaymentDisplayStatus::NeedsReview
- );
- assert_eq!(
TradeRevisionStatus::try_from_storage_key("none"),
Ok(TradeRevisionStatus::None)
);
@@ -3327,11 +2923,7 @@ mod tests {
);
let order_id = OrderId::new();
- let active_order = test_active_order_projection(
- RadrootsOrderStatus::Accepted,
- Some(RadrootsOrderFulfillmentState::ReadyForPickup),
- RadrootsOrderPaymentState::Recorded,
- );
+ let active_order = test_active_order_projection(RadrootsOrderStatus::Accepted);
let projection = TradeWorkflowProjection::from_active_order_projection(
order_id,
&active_order,
@@ -3341,15 +2933,9 @@ mod tests {
assert_eq!(projection.order_id, order_id);
assert_eq!(projection.agreement, TradeAgreementStatus::Confirmed);
assert_eq!(projection.revision, TradeRevisionStatus::Updated);
- assert_eq!(
- projection.fulfillment,
- Some(TradeFulfillmentStatus::ReadyForPickup)
- );
assert_eq!(projection.inventory, TradeInventoryStatus::Reserved);
- assert_eq!(projection.payment, TradePaymentDisplayStatus::Recorded);
assert_eq!(projection.economics.total_minor_units, Some(1234));
assert_eq!(projection.economics.currency_code.as_deref(), Some("USD"));
- assert!(!projection.payment.allows_payment_action());
assert_eq!(
projection.provenance,
TradeProvenanceProjection::from_primary_source(TradeWorkflowSource::LocalEvents)
@@ -3359,14 +2945,10 @@ mod tests {
);
assert_eq!(
order_status_from_active_order_projection(&active_order),
- Some(OrderStatus::Packed)
+ Some(OrderStatus::Scheduled)
);
- let requested_order = test_active_order_projection(
- RadrootsOrderStatus::Requested,
- None,
- RadrootsOrderPaymentState::NotRecorded,
- );
+ let requested_order = test_active_order_projection(RadrootsOrderStatus::Requested);
let requested_projection = TradeWorkflowProjection::from_active_order_projection(
order_id,
&requested_order,
@@ -3377,109 +2959,10 @@ mod tests {
requested_projection.agreement,
TradeAgreementStatus::Ordered
);
- assert_eq!(requested_projection.fulfillment, None);
- assert_eq!(
- requested_projection.payment,
- TradePaymentDisplayStatus::NotRecorded
- );
assert_eq!(
requested_projection.inventory,
TradeInventoryStatus::NeedsReview
);
-
- let invalid_payment_order = test_active_order_projection(
- RadrootsOrderStatus::Accepted,
- None,
- RadrootsOrderPaymentState::Invalid,
- );
- let invalid_payment_projection = TradeWorkflowProjection::from_active_order_projection(
- order_id,
- &invalid_payment_order,
- TradeRevisionStatus::None,
- TradeProvenanceProjection::from_primary_source(TradeWorkflowSource::LocalEvents),
- );
- assert_eq!(
- invalid_payment_projection.payment,
- TradePaymentDisplayStatus::NeedsReview
- );
-
- let mut pending_payment_order = test_active_order_projection(
- RadrootsOrderStatus::Accepted,
- None,
- RadrootsOrderPaymentState::Recorded,
- );
- pending_payment_order.payment.settlement_state = RadrootsOrderSettlementState::Pending;
- let pending_payment_projection = TradeWorkflowProjection::from_active_order_projection(
- order_id,
- &pending_payment_order,
- TradeRevisionStatus::None,
- TradeProvenanceProjection::from_primary_source(TradeWorkflowSource::LocalEvents),
- );
- assert_eq!(
- pending_payment_projection.payment,
- TradePaymentDisplayStatus::Pending
- );
-
- let settled_payment_order = test_active_order_projection(
- RadrootsOrderStatus::Completed,
- None,
- RadrootsOrderPaymentState::Settled,
- );
- let settled_payment_projection = TradeWorkflowProjection::from_active_order_projection(
- order_id,
- &settled_payment_order,
- TradeRevisionStatus::None,
- TradeProvenanceProjection::from_primary_source(TradeWorkflowSource::LocalEvents),
- );
- assert_eq!(
- settled_payment_projection.payment,
- TradePaymentDisplayStatus::Settled
- );
- }
-
- #[test]
- fn trade_payment_display_statuses_do_not_enable_payment_actions() {
- for status in [
- TradePaymentDisplayStatus::NotRecorded,
- TradePaymentDisplayStatus::Pending,
- TradePaymentDisplayStatus::Recorded,
- TradePaymentDisplayStatus::Settled,
- TradePaymentDisplayStatus::NeedsReview,
- ] {
- assert!(!status.allows_payment_action());
- }
- }
-
- #[test]
- fn trade_payment_display_projection_maps_reducer_payment_states() {
- let mut pending = RadrootsOrderPaymentProjection::not_recorded();
- pending.state = RadrootsOrderPaymentState::Recorded;
- pending.payment_event_id = Some(test_event_id(
- "4444444444444444444444444444444444444444444444444444444444444444",
- ));
- pending.settlement_state = RadrootsOrderSettlementState::Pending;
- assert_eq!(
- TradePaymentDisplayStatus::from_active_payment_projection(&pending),
- TradePaymentDisplayStatus::Pending
- );
-
- let mut settled = RadrootsOrderPaymentProjection::not_recorded();
- settled.state = RadrootsOrderPaymentState::Settled;
- settled.payment_event_id = Some(test_event_id(
- "4444444444444444444444444444444444444444444444444444444444444444",
- ));
- settled.settlement_state = RadrootsOrderSettlementState::Accepted;
- assert_eq!(
- TradePaymentDisplayStatus::from_active_payment_projection(&settled),
- TradePaymentDisplayStatus::Settled
- );
-
- let mut inconsistent = RadrootsOrderPaymentProjection::not_recorded();
- inconsistent.settlement_state = RadrootsOrderSettlementState::Accepted;
- assert_eq!(
- TradePaymentDisplayStatus::from_active_payment_projection(&inconsistent),
- TradePaymentDisplayStatus::NeedsReview
- );
}
#[test]
@@ -3544,28 +3027,11 @@ mod tests {
);
assert_eq!(TradeAgreementStatus::Ordered.storage_key(), "ordered");
assert_eq!(
- TradeFulfillmentStatus::from_active_fulfillment_status(
- &RadrootsOrderFulfillmentState::AcceptedNotFulfilled
- )
- .storage_key(),
- "confirmed"
- );
- assert_eq!(
- TradeFulfillmentStatus::ReadyForPickup.storage_key(),
- "ready_for_pickup"
- );
- assert_eq!(
TradeRevisionStatus::KeptAsPlaced.storage_key(),
"kept_as_placed"
);
assert_eq!(TradeInventoryStatus::Reserved.storage_key(), "reserved");
assert_eq!(
- TradePaymentDisplayStatus::NotRecorded.storage_key(),
- "not_recorded"
- );
- assert_eq!(TradePaymentDisplayStatus::Pending.storage_key(), "pending");
- assert_eq!(TradePaymentDisplayStatus::Settled.storage_key(), "settled");
- assert_eq!(
TradeWorkflowSource::LocalEvents.storage_key(),
"local_events"
);
@@ -3583,26 +3049,10 @@ mod tests {
"messages.trade.workflow.revision.change_proposed"
);
assert_eq!(
- TradeFulfillmentStatus::ReadyForPickup.label_key_id(),
- "messages.trade.workflow.fulfillment.ready_for_pickup"
- );
- assert_eq!(
TradeInventoryStatus::SoldOut.label_key_id(),
"messages.trade.workflow.inventory.sold_out"
);
assert_eq!(
- TradePaymentDisplayStatus::NotRecorded.label_key_id(),
- "messages.trade.workflow.payment.not_recorded"
- );
- assert_eq!(
- TradePaymentDisplayStatus::Pending.label_key_id(),
- "messages.trade.workflow.payment.pending"
- );
- assert_eq!(
- TradePaymentDisplayStatus::Settled.label_key_id(),
- "messages.trade.workflow.payment.settled"
- );
- assert_eq!(
TradeWorkflowSource::Cli.label_key_id(),
"messages.trade.workflow.provenance.cli"
);
@@ -3844,10 +3294,6 @@ mod tests {
None
);
assert_eq!(
- PackDayOutputOrderState::from_order_status(OrderStatus::Refunded),
- None
- );
- assert_eq!(
PackDayOutputOrderState::from_order_status(OrderStatus::NeedsReview),
None
);
@@ -3944,7 +3390,6 @@ mod tests {
currency_code: Some("USD".to_owned()),
..TradeEconomicsProjection::default()
};
- let order_payment = TradePaymentDisplayStatus::NotRecorded;
let orders_list = OrdersListProjection {
summary: OrdersListSummary {
total_orders: 3,
@@ -3965,8 +3410,7 @@ mod tests {
order_id,
OrderStatus::Scheduled,
),
- primary_action: Some(OrderPrimaryAction::PublishPreparing),
- fulfillment_actions: OrderFulfillmentAction::ALL.to_vec(),
+ primary_action: None,
}],
};
let order_detail = OrderDetailProjection {
@@ -3989,12 +3433,10 @@ mod tests {
line_total_minor_units: Some(1300),
}],
economics: order_economics.clone(),
- payment: order_payment,
workflow: TradeWorkflowProjection::from_order_status(order_id, OrderStatus::Scheduled)
- .with_economics_and_payment(order_economics, order_payment),
+ .with_economics(order_economics),
validation_receipts: Vec::new(),
- primary_action: Some(OrderPrimaryAction::PublishPreparing),
- fulfillment_actions: OrderFulfillmentAction::ALL.to_vec(),
+ primary_action: None,
recoveries: Vec::new(),
};
let pack_day = PackDayProjection {
@@ -4022,22 +3464,15 @@ mod tests {
assert!(orders_list.summary.has_orders());
assert!(!orders_list.is_empty());
- assert_eq!(
- orders_list.rows[0].primary_action,
- Some(OrderPrimaryAction::PublishPreparing)
- );
- assert_eq!(
- orders_list.rows[0].fulfillment_actions,
- OrderFulfillmentAction::ALL.to_vec()
- );
+ assert_eq!(orders_list.rows[0].primary_action, None);
assert_eq!(
orders_list.rows[0].workflow.agreement,
TradeAgreementStatus::Confirmed
);
assert_eq!(order_detail.items[0].quantity_display, "2 bags");
assert_eq!(
- order_detail.workflow.fulfillment,
- Some(TradeFulfillmentStatus::Confirmed)
+ order_detail.workflow.inventory,
+ TradeInventoryStatus::Reserved
);
assert!(!pack_day.is_empty());
assert_eq!(pack_day.pickup_roster[0].order_number, "R-1001");
@@ -4054,7 +3489,6 @@ mod tests {
currency_code: Some("USD".to_owned()),
..TradeEconomicsProjection::default()
};
- let buyer_order_payment = TradePaymentDisplayStatus::NotRecorded;
let listing = BuyerListingRow {
product_id,
farm_id,
@@ -4153,12 +3587,11 @@ mod tests {
line_total_minor_units: Some(1300),
}],
economics: buyer_order_economics.clone(),
- payment: buyer_order_payment,
workflow: TradeWorkflowProjection::from_buyer_order_status(
order_id,
BuyerOrderStatus::Scheduled,
)
- .with_economics_and_payment(buyer_order_economics, buyer_order_payment),
+ .with_economics(buyer_order_economics),
validation_receipts: Vec::new(),
order_note: Some("Leave by the cooler".to_owned()),
repeat_demand: None,
@@ -4204,7 +3637,6 @@ mod tests {
OrderStatus::Completed,
),
primary_action: None,
- fulfillment_actions: Vec::new(),
};
assert_eq!(today.orders_needing_action.len(), 1);
@@ -4294,18 +3726,15 @@ mod tests {
assert_eq!(ReminderSurface::PackDay.storage_key(), "pack_day");
assert_eq!(
- ReminderKind::RefundRecovery.storage_key(),
- "refund_recovery"
+ ReminderKind::MissedPickupRecovery.storage_key(),
+ "missed_pickup_recovery"
);
assert_eq!(ReminderUrgency::DueSoon.storage_key(), "due_soon");
assert_eq!(
ReminderDeliveryState::Acknowledged.storage_key(),
"acknowledged"
);
- assert_eq!(
- RecoveryKind::RefundFollowUp.storage_key(),
- "refund_follow_up"
- );
+ assert_eq!(RecoveryKind::MissedPickup.storage_key(), "missed_pickup");
assert_eq!(RecoveryState::InReview.storage_key(), "in_review");
assert_eq!(
RepeatDemandEligibility::Unavailable.storage_key(),