Skip to main content

adk_payments/kernel/
commands.rs

1use std::collections::BTreeMap;
2
3use adk_core::AdkIdentity;
4use chrono::{DateTime, Utc};
5use serde::{Deserialize, Serialize};
6
7use crate::domain::{
8    Cart, CommerceActor, CommerceMode, EvidenceReference, FulfillmentSelection, InterventionState,
9    MerchantRef, Money, OrderSnapshot, PaymentMethodSelection, PaymentProcessorRef,
10    ProtocolDescriptor, ProtocolExtensions, TransactionId, TransactionRecord,
11};
12
13/// Shared metadata supplied with canonical commerce commands.
14#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15#[serde(rename_all = "camelCase")]
16pub struct CommerceContext {
17    pub transaction_id: TransactionId,
18    #[serde(default, skip_serializing_if = "Option::is_none")]
19    pub session_identity: Option<AdkIdentity>,
20    pub actor: CommerceActor,
21    pub merchant_of_record: MerchantRef,
22    #[serde(default, skip_serializing_if = "Option::is_none")]
23    pub payment_processor: Option<PaymentProcessorRef>,
24    pub mode: CommerceMode,
25    pub protocol: ProtocolDescriptor,
26    #[serde(default, skip_serializing_if = "ProtocolExtensions::is_empty")]
27    pub extensions: ProtocolExtensions,
28}
29
30/// Canonical request to create a checkout session or AP2 cart negotiation.
31#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
32#[serde(rename_all = "camelCase")]
33pub struct CreateCheckoutCommand {
34    pub context: CommerceContext,
35    pub cart: Cart,
36    #[serde(default, skip_serializing_if = "Option::is_none")]
37    pub fulfillment: Option<FulfillmentSelection>,
38}
39
40/// Canonical request to update checkout state before payment execution.
41#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
42#[serde(rename_all = "camelCase")]
43pub struct UpdateCheckoutCommand {
44    pub context: CommerceContext,
45    #[serde(default, skip_serializing_if = "Option::is_none")]
46    pub cart: Option<Cart>,
47    #[serde(default, skip_serializing_if = "Option::is_none")]
48    pub fulfillment: Option<FulfillmentSelection>,
49}
50
51/// Canonical request to finalize checkout and produce an order.
52#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
53#[serde(rename_all = "camelCase")]
54pub struct CompleteCheckoutCommand {
55    pub context: CommerceContext,
56    #[serde(default, skip_serializing_if = "Option::is_none")]
57    pub selected_payment_method: Option<PaymentMethodSelection>,
58    #[serde(default, skip_serializing_if = "ProtocolExtensions::is_empty")]
59    pub extensions: ProtocolExtensions,
60}
61
62/// Canonical request to cancel a checkout or transaction.
63#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
64#[serde(rename_all = "camelCase")]
65pub struct CancelCheckoutCommand {
66    pub context: CommerceContext,
67    #[serde(default, skip_serializing_if = "Option::is_none")]
68    pub reason: Option<String>,
69    #[serde(default, skip_serializing_if = "ProtocolExtensions::is_empty")]
70    pub extensions: ProtocolExtensions,
71}
72
73/// Canonical order-state update emitted after checkout completion.
74#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
75#[serde(rename_all = "camelCase")]
76pub struct OrderUpdateCommand {
77    pub context: CommerceContext,
78    pub order: OrderSnapshot,
79}
80
81/// Canonical payment-execution request shared by ACP and AP2 adapters.
82#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
83#[serde(rename_all = "camelCase")]
84pub struct ExecutePaymentCommand {
85    pub context: CommerceContext,
86    pub amount: Money,
87    #[serde(default, skip_serializing_if = "Option::is_none")]
88    pub selected_payment_method: Option<PaymentMethodSelection>,
89    #[serde(default, skip_serializing_if = "Vec::is_empty")]
90    pub supporting_evidence_refs: Vec<EvidenceReference>,
91    #[serde(default, skip_serializing_if = "ProtocolExtensions::is_empty")]
92    pub extensions: ProtocolExtensions,
93}
94
95/// Canonical payment outcome type used by the execution service.
96#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
97#[serde(rename_all = "snake_case")]
98pub enum PaymentExecutionOutcome {
99    Authorized,
100    Completed,
101    InterventionRequired,
102    Failed,
103}
104
105/// Canonical payment execution result returned by payment backends.
106#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
107#[serde(rename_all = "camelCase")]
108pub struct PaymentExecutionResult {
109    pub outcome: PaymentExecutionOutcome,
110    pub transaction: TransactionRecord,
111    #[serde(default, skip_serializing_if = "Option::is_none")]
112    pub order: Option<OrderSnapshot>,
113    #[serde(default, skip_serializing_if = "Option::is_none")]
114    pub intervention: Option<InterventionState>,
115    #[serde(default, skip_serializing_if = "Vec::is_empty")]
116    pub generated_evidence_refs: Vec<EvidenceReference>,
117}
118
119/// Canonical delegated-payment allowance preserved across protocol adapters.
120#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
121#[serde(rename_all = "camelCase")]
122pub struct DelegatePaymentAllowance {
123    pub reason: String,
124    pub max_amount: Money,
125    pub merchant_id: String,
126    pub checkout_session_id: String,
127    pub expires_at: DateTime<Utc>,
128    #[serde(default, skip_serializing_if = "ProtocolExtensions::is_empty")]
129    pub extensions: ProtocolExtensions,
130}
131
132/// Canonical risk signal attached to delegated-payment requests.
133#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
134#[serde(rename_all = "camelCase")]
135pub struct DelegatedRiskSignal {
136    pub signal_type: String,
137    pub score: i64,
138    pub action: String,
139    #[serde(default, skip_serializing_if = "ProtocolExtensions::is_empty")]
140    pub extensions: ProtocolExtensions,
141}
142
143/// Canonical request to tokenize or delegate a payment credential.
144#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
145#[serde(rename_all = "camelCase")]
146pub struct DelegatePaymentCommand {
147    pub context: CommerceContext,
148    #[serde(default, skip_serializing_if = "Option::is_none")]
149    pub selected_payment_method: Option<PaymentMethodSelection>,
150    pub allowance: DelegatePaymentAllowance,
151    #[serde(default, skip_serializing_if = "Option::is_none")]
152    pub billing_address: Option<serde_json::Value>,
153    #[serde(default, skip_serializing_if = "Vec::is_empty")]
154    pub risk_signals: Vec<DelegatedRiskSignal>,
155    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
156    pub metadata: BTreeMap<String, String>,
157    #[serde(default, skip_serializing_if = "ProtocolExtensions::is_empty")]
158    pub extensions: ProtocolExtensions,
159}
160
161/// Canonical delegated-payment result returned by payment-token services.
162#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
163#[serde(rename_all = "camelCase")]
164pub struct DelegatedPaymentResult {
165    pub delegated_payment_id: String,
166    pub created_at: DateTime<Utc>,
167    #[serde(default, skip_serializing_if = "Option::is_none")]
168    pub transaction: Option<TransactionRecord>,
169    #[serde(default, skip_serializing_if = "Vec::is_empty")]
170    pub generated_evidence_refs: Vec<EvidenceReference>,
171    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
172    pub metadata: BTreeMap<String, String>,
173    #[serde(default, skip_serializing_if = "ProtocolExtensions::is_empty")]
174    pub extensions: ProtocolExtensions,
175}
176
177/// Canonical request to sync asynchronous payment outcomes back into the kernel.
178#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
179#[serde(rename_all = "camelCase")]
180pub struct SyncPaymentOutcomeCommand {
181    pub context: CommerceContext,
182    pub outcome: PaymentExecutionOutcome,
183    #[serde(default, skip_serializing_if = "Option::is_none")]
184    pub order: Option<OrderSnapshot>,
185    #[serde(default, skip_serializing_if = "Option::is_none")]
186    pub intervention: Option<InterventionState>,
187    #[serde(default, skip_serializing_if = "Vec::is_empty")]
188    pub generated_evidence_refs: Vec<EvidenceReference>,
189}
190
191/// Canonical request to start an intervention flow.
192#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
193#[serde(rename_all = "camelCase")]
194pub struct BeginInterventionCommand {
195    pub context: CommerceContext,
196    pub intervention: InterventionState,
197}
198
199/// Canonical request to resume or complete an intervention flow.
200#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
201#[serde(rename_all = "camelCase")]
202pub struct ContinueInterventionCommand {
203    pub context: CommerceContext,
204    pub intervention_id: String,
205    #[serde(default, skip_serializing_if = "Option::is_none")]
206    pub continuation_token: Option<String>,
207    #[serde(default, skip_serializing_if = "Option::is_none")]
208    pub result_summary: Option<String>,
209    #[serde(default, skip_serializing_if = "ProtocolExtensions::is_empty")]
210    pub extensions: ProtocolExtensions,
211}
212
213/// Canonical lookup by transaction identifier and optional session identity.
214#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
215#[serde(rename_all = "camelCase")]
216pub struct TransactionLookup {
217    pub transaction_id: TransactionId,
218    #[serde(default, skip_serializing_if = "Option::is_none")]
219    pub session_identity: Option<AdkIdentity>,
220}
221
222/// Canonical request to list unresolved transactions.
223#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
224#[serde(rename_all = "camelCase")]
225pub struct ListUnresolvedTransactionsRequest {
226    #[serde(default, skip_serializing_if = "Option::is_none")]
227    pub session_identity: Option<AdkIdentity>,
228}
229
230/// Canonical lookup for one stored evidence artifact.
231#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
232#[serde(rename_all = "camelCase")]
233pub struct EvidenceLookup {
234    pub evidence_ref: EvidenceReference,
235    #[serde(default, skip_serializing_if = "Option::is_none")]
236    pub session_identity: Option<AdkIdentity>,
237}
238
239/// Canonical request to persist one evidence artifact.
240#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
241#[serde(rename_all = "camelCase")]
242pub struct StoreEvidenceCommand {
243    pub transaction_id: TransactionId,
244    #[serde(default, skip_serializing_if = "Option::is_none")]
245    pub session_identity: Option<AdkIdentity>,
246    pub evidence_ref: EvidenceReference,
247    pub body: Vec<u8>,
248    pub content_type: String,
249}
250
251/// Stored evidence returned by the evidence store.
252#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
253#[serde(rename_all = "camelCase")]
254pub struct StoredEvidence {
255    pub evidence_ref: EvidenceReference,
256    pub body: Vec<u8>,
257    pub content_type: String,
258}