futu_backend/trade_query/orders/
order_info.rs1use bytes::Bytes;
2use futu_cache::trd_cache::{CachedOrder, TrdCache};
3use futu_command_spec::{TradeQueryEnvironment, TradeQueryOperation, trade::trade_query_route};
4use futu_core::error::{FutuError, Result};
5use futu_domain_trade_history::detail_request::{
6 CurrentTradeDetailRequestPlan, plan_current_trade_detail_request_like_cpp,
7};
8use prost::Message;
9
10use crate::command_runtime::execute_trade_read;
11use crate::conn::BackendConn;
12use crate::proto_internal::{order_sys_interface, sim_order_sys_interface};
13
14use super::builders::build_order_info_req_base;
15use super::cipher::current_trade_query_real_cipher_or_error_like_cpp;
16use super::helpers::derive_acc_query_context;
17use super::projection::{
18 order_proto_to_cached_with_jp_acc_type_like_cpp, sim_order_proto_to_cached_like_cpp,
19};
20use super::status_helpers::{
21 backend_order_info_status_by_account_like_cpp, backend_order_info_status_like_cpp,
22};
23use super::types::QueryErrorMode;
24
25pub async fn query_order_info_strict_for_push_refresh(
33 backend: &BackendConn,
34 acc_id: u64,
35 trd_cache: &TrdCache,
36 order_ids: &[String],
37 security_type: Option<u32>,
38 exchange: Option<&str>,
39) -> Result<Vec<CachedOrder>> {
40 let filtered_ids = match plan_current_trade_detail_request_like_cpp(order_ids) {
41 CurrentTradeDetailRequestPlan::SkipEmpty => return Ok(vec![]),
42 CurrentTradeDetailRequestPlan::Query { filtered_ids } => filtered_ids,
43 };
44
45 let (trd_env, _account_trd_market, _enabled_markets) =
46 derive_acc_query_context(trd_cache, acc_id);
47 let environment = if trd_env == 1 {
48 TradeQueryEnvironment::Real
49 } else {
50 TradeQueryEnvironment::Sim
51 };
52 let route =
53 trade_query_route(TradeQueryOperation::OrderInfo, environment).ok_or_else(|| {
54 FutuError::Codec(format!(
55 "QueryOrderInfo has no registered {environment:?} backend route"
56 ))
57 })?;
58 let cmd_id = route.cmd_id;
59 let real_cipher = if trd_env == 1 {
60 current_trade_query_real_cipher_or_error_like_cpp(
61 acc_id,
62 trd_cache,
63 QueryErrorMode::StrictPushRefresh,
64 "QueryOrderInfo",
65 )?
66 } else {
67 Vec::new()
68 };
69 let trade_cipher = (trd_env == 1).then_some(real_cipher.as_slice());
70 let req = build_order_info_req_base(
71 acc_id,
72 security_type,
73 exchange,
74 &filtered_ids,
75 real_cipher.clone(),
76 );
77 let resp = execute_trade_read(
78 backend,
79 TradeQueryOperation::OrderInfo,
80 environment,
81 trade_cipher,
82 Bytes::from(req.encode_to_vec()),
83 )
84 .await?;
85 let (orders, received): (Vec<CachedOrder>, usize) = if trd_env == 1 {
86 let parsed: order_sys_interface::OrderDetailRsp = Message::decode(resp.body.as_ref())?;
87 if let Err(status_err) = backend_order_info_status_like_cpp(
88 parsed.result,
89 parsed.msg_header.as_ref(),
90 parsed.err_msg.as_deref(),
91 acc_id,
92 filtered_ids.len(),
93 parsed.orders.len(),
94 ) {
95 return Err(FutuError::ServerError {
96 ret_type: status_err.result,
97 msg: format!("{} (acc_id={acc_id})", status_err.message),
98 });
99 }
100 let received = parsed.orders.len();
101 let orders = parsed
102 .orders
103 .iter()
104 .filter_map(|order| {
105 let jp_acc_type = order
106 .sub_account_id
107 .and_then(|id| trd_cache.jp_acc_type_for_sub_account(acc_id, id));
108 order_proto_to_cached_with_jp_acc_type_like_cpp(trd_env, order, jp_acc_type)
109 })
110 .collect();
111 (orders, received)
112 } else {
113 let parsed: sim_order_sys_interface::OrderDetailRsp = Message::decode(resp.body.as_ref())?;
114 if let Err(status_err) = backend_order_info_status_by_account_like_cpp(
115 parsed.result,
116 parsed
117 .msg_header
118 .as_ref()
119 .and_then(|header| header.account_id),
120 parsed.err_msg.as_deref(),
121 acc_id,
122 filtered_ids.len(),
123 parsed.orders.len(),
124 ) {
125 return Err(FutuError::ServerError {
126 ret_type: status_err.result,
127 msg: format!("{} (acc_id={acc_id})", status_err.message),
128 });
129 }
130 let received = parsed.orders.len();
131 let orders = parsed
132 .orders
133 .iter()
134 .filter_map(|order| sim_order_proto_to_cached_like_cpp(trd_env, order))
135 .collect();
136 (orders, received)
137 };
138 let mut applied_orders = Vec::with_capacity(orders.len());
139 for order in orders {
140 if trd_cache.upsert_order(acc_id, order.clone()) {
141 applied_orders.push(order);
142 }
143 }
144 tracing::debug!(
145 cmd_id,
146 requested = filtered_ids.len(),
147 received,
148 applied = applied_orders.len(),
149 "order details queried"
150 );
151 Ok(applied_orders)
152}