Skip to main content

esi_openapi/groups/
contracts.rs

1use crate::prelude::*;
2
3/// Endpoints for Contracts
4pub struct ContractsGroup<'a> {
5    pub(crate) esi: &'a Esi,
6}
7
8/// The type of a contract.
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
10#[serde(rename_all = "snake_case")]
11pub enum ContractType {
12    /// The type is not known.
13    Unknown,
14    /// An item exchange.
15    ItemExchange,
16    /// An auction.
17    Auction,
18    /// A courier contract.
19    Courier,
20    /// A loan.
21    Loan,
22    /// A type this version of the crate does not know about.
23    #[serde(other)]
24    Unrecognized,
25}
26
27/// A public contract in a region.
28#[derive(Debug, Clone, PartialEq, Deserialize)]
29#[allow(missing_docs)]
30pub struct PublicContract {
31    pub buyout: Option<f64>,
32    pub collateral: Option<f64>,
33    pub contract_id: i64,
34    pub date_expired: String,
35    pub date_issued: String,
36    pub days_to_complete: Option<i64>,
37    pub end_location_id: Option<i64>,
38    pub for_corporation: Option<bool>,
39    pub issuer_corporation_id: i64,
40    /// Character ID of the issuer.
41    pub issuer_id: i64,
42    pub price: Option<f64>,
43    pub reward: Option<f64>,
44    pub start_location_id: Option<i64>,
45    pub title: Option<String>,
46    #[serde(rename = "type")]
47    pub contract_type: ContractType,
48    pub volume: Option<f64>,
49}
50
51/// A bid on a public auction contract.
52#[derive(Debug, Clone, PartialEq, Deserialize)]
53#[allow(missing_docs)]
54pub struct PublicContractBid {
55    pub amount: f64,
56    pub bid_id: i64,
57    pub date_bid: String,
58}
59
60/// An item of a public contract.
61#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
62#[allow(missing_docs)]
63pub struct PublicContractItem {
64    pub is_blueprint_copy: Option<bool>,
65    pub is_included: bool,
66    pub item_id: Option<i64>,
67    pub material_efficiency: Option<i64>,
68    pub quantity: i64,
69    pub record_id: i64,
70    pub runs: Option<i64>,
71    pub time_efficiency: Option<i64>,
72    pub type_id: i64,
73}
74
75/// Who can accept a contract.
76#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
77#[serde(rename_all = "snake_case")]
78pub enum ContractAvailability {
79    /// Anyone.
80    Public,
81    /// A specific character or corporation.
82    Personal,
83    /// Members of a corporation.
84    Corporation,
85    /// Members of an alliance.
86    Alliance,
87    /// A value this version of the crate does not know about.
88    #[serde(other)]
89    Unrecognized,
90}
91
92/// The status of a contract.
93#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
94#[serde(rename_all = "snake_case")]
95pub enum ContractStatus {
96    /// Waiting for an acceptor.
97    Outstanding,
98    /// Accepted and in progress.
99    InProgress,
100    /// Finished by the issuer.
101    FinishedIssuer,
102    /// Finished by the contractor.
103    FinishedContractor,
104    /// Finished.
105    Finished,
106    /// Cancelled.
107    Cancelled,
108    /// Rejected.
109    Rejected,
110    /// Failed.
111    Failed,
112    /// Deleted.
113    Deleted,
114    /// Reversed.
115    Reversed,
116    /// A value this version of the crate does not know about.
117    #[serde(other)]
118    Unrecognized,
119}
120
121/// A contract of a character or a corporation.
122#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
123pub struct Contract {
124    /// ID of the character or corporation that accepted the contract
125    /// (`0` if nobody did).
126    pub acceptor_id: i64,
127    /// ID of the character, corporation or alliance the contract is assigned to.
128    pub assignee_id: i64,
129    /// Who can accept the contract.
130    pub availability: ContractAvailability,
131    /// Buyout price (auctions).
132    pub buyout: Option<f64>,
133    /// Collateral (couriers).
134    pub collateral: Option<f64>,
135    /// ID of the contract.
136    pub contract_id: i64,
137    /// Date the contract was accepted.
138    pub date_accepted: Option<String>,
139    /// Date the contract was completed.
140    pub date_completed: Option<String>,
141    /// Date the contract expires.
142    pub date_expired: String,
143    /// Date the contract was issued.
144    pub date_issued: String,
145    /// Days to complete (couriers).
146    pub days_to_complete: Option<i64>,
147    /// Destination location (couriers).
148    pub end_location_id: Option<i64>,
149    /// Whether the contract was issued on behalf of a corporation.
150    pub for_corporation: bool,
151    /// Corporation ID of the issuer.
152    pub issuer_corporation_id: i64,
153    /// Character ID of the issuer.
154    pub issuer_id: i64,
155    /// Price (item exchanges and auctions).
156    pub price: Option<f64>,
157    /// Reward (couriers).
158    pub reward: Option<f64>,
159    /// Start location.
160    pub start_location_id: Option<i64>,
161    /// Status of the contract.
162    pub status: ContractStatus,
163    /// Title of the contract.
164    pub title: Option<String>,
165    /// Type of the contract.
166    #[serde(rename = "type")]
167    pub contract_type: ContractType,
168    /// Volume of the items, in m3.
169    pub volume: Option<f64>,
170}
171
172/// A bid on an auction contract.
173#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
174pub struct ContractBid {
175    /// Amount of the bid.
176    pub amount: f64,
177    /// ID of the bid.
178    pub bid_id: i64,
179    /// Character ID of the bidder.
180    pub bidder_id: i64,
181    /// Date of the bid.
182    pub date_bid: String,
183}
184
185/// An item of a contract.
186#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
187pub struct ContractItem {
188    /// Whether the item is offered (`true`) or requested (`false`).
189    pub is_included: bool,
190    /// Whether the item is a singleton (assembled).
191    pub is_singleton: bool,
192    /// Quantity of the item.
193    pub quantity: i64,
194    /// Raw quantity, used for blueprints and damaged items.
195    pub raw_quantity: Option<i64>,
196    /// ID of the record.
197    pub record_id: i64,
198    /// Type ID of the item.
199    pub type_id: i64,
200}
201
202impl ContractsGroup<'_> {
203    api_get!(
204        /// List the bids on a public auction contract.
205        get_public_contract_bids,
206        "GetContractsPublicBidsContractId",
207        RequestType::Public,
208        Vec<PublicContractBid>,
209        (contract_id: i64) => "{contract_id}";
210        Optional(page: i32) => "page"
211    );
212
213    api_get!(
214        /// List the items of a public contract.
215        get_public_contract_items,
216        "GetContractsPublicItemsContractId",
217        RequestType::Public,
218        Vec<PublicContractItem>,
219        (contract_id: i64) => "{contract_id}";
220        Optional(page: i32) => "page"
221    );
222
223    api_get!(
224        /// List the public contracts in a region.
225        get_public_contracts,
226        "GetContractsPublicRegionId",
227        RequestType::Public,
228        Vec<PublicContract>,
229        (region_id: i64) => "{region_id}";
230        Optional(page: i32) => "page"
231    );
232
233    api_get!(
234        /// List the contracts of a character.
235        get_character_contracts,
236        "GetCharactersCharacterIdContracts",
237        RequestType::Authenticated,
238        Vec<Contract>,
239        (character_id: i64) => "{character_id}";
240        Optional(page: i32) => "page"
241    );
242
243    api_get!(
244        /// List the bids on an auction contract of a character.
245        get_character_contract_bids,
246        "GetCharactersCharacterIdContractsContractIdBids",
247        RequestType::Authenticated,
248        Vec<ContractBid>,
249        (character_id: i64) => "{character_id}",
250        (contract_id: i64) => "{contract_id}"
251    );
252
253    api_get!(
254        /// List the items of a contract of a character.
255        get_character_contract_items,
256        "GetCharactersCharacterIdContractsContractIdItems",
257        RequestType::Authenticated,
258        Vec<ContractItem>,
259        (character_id: i64) => "{character_id}",
260        (contract_id: i64) => "{contract_id}"
261    );
262
263    api_get!(
264        /// List the contracts of a corporation.
265        get_corporation_contracts,
266        "GetCorporationsCorporationIdContracts",
267        RequestType::Authenticated,
268        Vec<Contract>,
269        (corporation_id: i64) => "{corporation_id}";
270        Optional(page: i32) => "page"
271    );
272
273    api_get!(
274        /// List the bids on an auction contract of a corporation.
275        get_corporation_contract_bids,
276        "GetCorporationsCorporationIdContractsContractIdBids",
277        RequestType::Authenticated,
278        Vec<ContractBid>,
279        (corporation_id: i64) => "{corporation_id}",
280        (contract_id: i64) => "{contract_id}";
281        Optional(page: i32) => "page"
282    );
283
284    api_get!(
285        /// List the items of a contract of a corporation.
286        get_corporation_contract_items,
287        "GetCorporationsCorporationIdContractsContractIdItems",
288        RequestType::Authenticated,
289        Vec<ContractItem>,
290        (corporation_id: i64) => "{corporation_id}",
291        (contract_id: i64) => "{contract_id}"
292    );
293}
294
295#[cfg(test)]
296mod tests {
297    use super::{ContractType, PublicContract};
298
299    #[test]
300    fn test_parse_contract_and_unknown_type() {
301        let base = |kind: &str| {
302            format!(
303                r#"{{"contract_id": 1, "date_expired": "2026-01-02T00:00:00Z",
304                "date_issued": "2026-01-01T00:00:00Z", "issuer_corporation_id": 98000001,
305                "issuer_id": 2112000000, "type": "{kind}"}}"#
306            )
307        };
308        let known: PublicContract = serde_json::from_str(&base("item_exchange")).unwrap();
309        assert_eq!(known.contract_type, ContractType::ItemExchange);
310        let unknown: PublicContract = serde_json::from_str(&base("brand_new")).unwrap();
311        assert_eq!(unknown.contract_type, ContractType::Unrecognized);
312    }
313}
314
315#[cfg(test)]
316mod private_contract_tests {
317    use super::*;
318
319    #[test]
320    fn test_parse_private_contract() {
321        let json = r#"[{"acceptor_id": 0, "assignee_id": 2112625428, "availability": "personal",
322            "contract_id": 300000000, "date_expired": "e", "date_issued": "i",
323            "for_corporation": false, "issuer_corporation_id": 98000001, "issuer_id": 2112000000,
324            "status": "finished_issuer", "type": "courier", "reward": 1000.0},
325            {"acceptor_id": 0, "assignee_id": 0, "availability": "x", "contract_id": 1,
326            "date_expired": "e", "date_issued": "i", "for_corporation": true,
327            "issuer_corporation_id": 1, "issuer_id": 1, "status": "later", "type": "loan"}]"#;
328        let c: Vec<Contract> = serde_json::from_str(json).unwrap();
329        assert_eq!(c[0].status, ContractStatus::FinishedIssuer);
330        assert_eq!(c[0].availability, ContractAvailability::Personal);
331        assert_eq!(c[1].status, ContractStatus::Unrecognized);
332        assert_eq!(c[1].availability, ContractAvailability::Unrecognized);
333    }
334
335    #[test]
336    fn test_parse_bids_and_items() {
337        let b: Vec<ContractBid> = serde_json::from_str(
338            r#"[{"amount": 5.5, "bid_id": 1, "bidder_id": 2112000000, "date_bid": "d"}]"#,
339        )
340        .unwrap();
341        assert_eq!(b[0].bidder_id, 2_112_000_000);
342        let i: Vec<ContractItem> = serde_json::from_str(
343            r#"[{"is_included": true, "is_singleton": false, "quantity": 5000000000,
344                 "record_id": 9, "type_id": 34}]"#,
345        )
346        .unwrap();
347        assert_eq!(i[0].quantity, 5_000_000_000);
348        assert_eq!(i[0].raw_quantity, None);
349    }
350}