dceapi_rs/services/
delivery.rs

1//! Delivery service for delivery data APIs.
2
3use crate::error::{Error, Result};
4use crate::http::{BaseClient, RequestOptions};
5use crate::models::{
6    BondedDelivery, BondedDeliveryRequest, DeliveryCost, DeliveryData, DeliveryDataRequest,
7    DeliveryMatch, DeliveryMatchRequest, FactorySpotAgio, FactorySpotAgioRequest,
8    PlywoodDeliveryCommodity, PlywoodDeliveryCommodityRequest, RollDeliverySellerIntention,
9    RollDeliverySellerIntentionRequest, TcCongregateDelivery, TcCongregateDeliveryRequest,
10    TdBondedDelivery, TdBondedDeliveryRequest, WarehousePremiumResponse,
11};
12
13/// API endpoint for delivery data.
14const PATH_GET_DELIVERY_DATA: &str = "/dceapi/forward/publicweb/deliverystat/delivery";
15
16/// API endpoint for delivery match data.
17const PATH_GET_DELIVERY_MATCH: &str = "/dceapi/forward/publicweb/deliverystat/deliveryMatch";
18
19/// API endpoint for delivery costs.
20const PATH_GET_DELIVERY_COST: &str = "/dceapi/forward/publicweb/deliverypara/deliveryCosts";
21
22/// API endpoint for warehouse premium.
23const PATH_GET_WAREHOUSE_PREMIUM: &str = "/dceapi/forward/publicweb/deliverypara/floatingAgio";
24
25/// API endpoint for TC congregate delivery statistics.
26const PATH_GET_TC_CONGREGATE_DELIVERY: &str =
27    "/dceapi/forward/publicweb/DeliveryStatistics/tcCongregateDeliveryQuotes";
28
29/// API endpoint for roll delivery seller intention.
30const PATH_GET_ROLL_DELIVERY_SELLER_INTENTION: &str =
31    "/dceapi/forward/publicweb/DeliveryStatistics/rollDeliverySellerIntention";
32
33/// API endpoint for bonded delivery settlement price.
34const PATH_GET_BONDED_DELIVERY: &str = "/dceapi/forward/publicweb/quotesdata/bondedDelivery";
35
36/// API endpoint for TD bonded delivery settlement price.
37const PATH_GET_TD_BONDED_DELIVERY: &str = "/dceapi/forward/publicweb/quotesdata/tdBondedDelivery";
38
39/// API endpoint for factory spot premium (basis spread for fiberboard).
40const PATH_GET_FACTORY_SPOT_AGIO: &str =
41    "/dceapi/forward/publicweb/quotesdata/queryFactorySpotAgioQuotes";
42
43/// API endpoint for plywood delivery commodity information.
44const PATH_GET_PLYWOOD_DELIVERY_COMMODITY: &str =
45    "/dceapi/forward/publicweb/deliverystat/queryPlywoodDeliveryCommodity";
46
47/// Delivery service for accessing delivery-related data.
48#[derive(Debug, Clone)]
49pub struct DeliveryService {
50    client: BaseClient,
51}
52
53impl DeliveryService {
54    /// Create a new delivery service.
55    pub fn new(client: BaseClient) -> Self {
56        DeliveryService { client }
57    }
58
59    /// Get delivery data.
60    ///
61    /// # Arguments
62    /// * `req` - Request with variety code and trade date
63    /// * `opts` - Optional request options
64    pub async fn get_delivery_data(
65        &self,
66        req: &DeliveryDataRequest,
67        opts: Option<RequestOptions>,
68    ) -> Result<Vec<DeliveryData>> {
69        self.client.do_post(PATH_GET_DELIVERY_DATA, req, opts).await
70    }
71
72    /// Get delivery match data.
73    ///
74    /// # Arguments
75    /// * `req` - Request with variety code and trade date
76    /// * `opts` - Optional request options
77    pub async fn get_delivery_match(
78        &self,
79        req: &DeliveryMatchRequest,
80        opts: Option<RequestOptions>,
81    ) -> Result<Vec<DeliveryMatch>> {
82        self.client
83            .do_post(PATH_GET_DELIVERY_MATCH, req, opts)
84            .await
85    }
86
87    /// Get delivery cost for a variety.
88    ///
89    /// # Arguments
90    /// * `variety_id` - Variety ID ("all" for all varieties)
91    /// * `variety_type` - Variety type ("0" = physical delivery, "1" = average price delivery)
92    /// * `opts` - Optional request options
93    pub async fn get_delivery_cost(
94        &self,
95        variety_id: &str,
96        variety_type: &str,
97        opts: Option<RequestOptions>,
98    ) -> Result<Vec<DeliveryCost>> {
99        if variety_id.is_empty() {
100            return Err(Error::validation("variety_id", "variety_id is required"));
101        }
102
103        #[derive(serde::Serialize)]
104        #[serde(rename_all = "camelCase")]
105        struct Request<'a> {
106            variety_id: &'a str,
107            variety_type: &'a str,
108            lang: &'a str,
109        }
110
111        let req = Request {
112            variety_id,
113            variety_type,
114            lang: "zh",
115        };
116        self.client
117            .do_post(PATH_GET_DELIVERY_COST, &req, opts)
118            .await
119    }
120
121    /// Get warehouse premium for a variety.
122    ///
123    /// # Arguments
124    /// * `variety_id` - Variety ID
125    /// * `trade_date` - Trade date (YYYYMMDD format)
126    /// * `opts` - Optional request options
127    pub async fn get_warehouse_premium(
128        &self,
129        variety_id: &str,
130        trade_date: &str,
131        opts: Option<RequestOptions>,
132    ) -> Result<WarehousePremiumResponse> {
133        if variety_id.is_empty() {
134            return Err(Error::validation("variety_id", "variety_id is required"));
135        }
136
137        #[derive(serde::Serialize)]
138        #[serde(rename_all = "camelCase")]
139        struct Request<'a> {
140            variety_id: &'a str,
141            trade_date: &'a str,
142        }
143
144        let req = Request {
145            variety_id,
146            trade_date,
147        };
148        self.client
149            .do_post(PATH_GET_WAREHOUSE_PREMIUM, &req, opts)
150            .await
151    }
152
153    /// Get TC (two-way delivery) congregate delivery statistics.
154    ///
155    /// Returns aggregated delivery information for varieties supporting two-way delivery.
156    ///
157    /// # Arguments
158    /// * `req` - Request with variety_id and trade_date
159    /// * `opts` - Optional request options
160    pub async fn get_tc_congregate_delivery(
161        &self,
162        req: &TcCongregateDeliveryRequest,
163        opts: Option<RequestOptions>,
164    ) -> Result<Vec<TcCongregateDelivery>> {
165        self.client
166            .do_post(PATH_GET_TC_CONGREGATE_DELIVERY, req, opts)
167            .await
168    }
169
170    /// Get roll delivery seller intention.
171    ///
172    /// Returns seller's delivery intentions for rolling delivery contracts.
173    ///
174    /// # Arguments
175    /// * `req` - Request with variety_id and trade_date
176    /// * `opts` - Optional request options
177    pub async fn get_roll_delivery_seller_intention(
178        &self,
179        req: &RollDeliverySellerIntentionRequest,
180        opts: Option<RequestOptions>,
181    ) -> Result<Vec<RollDeliverySellerIntention>> {
182        self.client
183            .do_post(PATH_GET_ROLL_DELIVERY_SELLER_INTENTION, req, opts)
184            .await
185    }
186
187    /// Get bonded delivery data.
188    ///
189    /// Returns delivery statistics for bonded warehouse delivery mode.
190    ///
191    /// # Arguments
192    /// * `req` - Request with variety_id and trade_date
193    /// * `opts` - Optional request options
194    pub async fn get_bonded_delivery(
195        &self,
196        req: &BondedDeliveryRequest,
197        opts: Option<RequestOptions>,
198    ) -> Result<Vec<BondedDelivery>> {
199        self.client
200            .do_post(PATH_GET_BONDED_DELIVERY, req, opts)
201            .await
202    }
203
204    /// Get TD (two-day) bonded delivery data.
205    ///
206    /// Returns bonded delivery data with two-day settlement mode.
207    ///
208    /// # Arguments
209    /// * `req` - Request with variety_id and trade_date
210    /// * `opts` - Optional request options
211    pub async fn get_td_bonded_delivery(
212        &self,
213        req: &TdBondedDeliveryRequest,
214        opts: Option<RequestOptions>,
215    ) -> Result<Vec<TdBondedDelivery>> {
216        self.client
217            .do_post(PATH_GET_TD_BONDED_DELIVERY, req, opts)
218            .await
219    }
220
221    /// Get factory spot premium (basis spread).
222    ///
223    /// Returns the difference between factory spot price and futures price.
224    ///
225    /// # Arguments
226    /// * `req` - Request with variety_id
227    /// * `opts` - Optional request options
228    pub async fn get_factory_spot_agio(
229        &self,
230        req: &FactorySpotAgioRequest,
231        opts: Option<RequestOptions>,
232    ) -> Result<Vec<FactorySpotAgio>> {
233        self.client
234            .do_post(PATH_GET_FACTORY_SPOT_AGIO, req, opts)
235            .await
236    }
237
238    /// Get plywood delivery commodity information.
239    ///
240    /// Returns delivery specifications and parameters specific to plywood contracts.
241    ///
242    /// # Arguments
243    /// * `req` - Request with variety_id
244    /// * `opts` - Optional request options
245    pub async fn get_plywood_delivery_commodity(
246        &self,
247        req: &PlywoodDeliveryCommodityRequest,
248        opts: Option<RequestOptions>,
249    ) -> Result<Vec<PlywoodDeliveryCommodity>> {
250        self.client
251            .do_post(PATH_GET_PLYWOOD_DELIVERY_COMMODITY, req, opts)
252            .await
253    }
254}