use super::*;
use crate::error::Result as DeribitFixResult;
use crate::message::builder::MessageBuilder;
use crate::model::types::MsgType;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
#[derive(Clone, PartialEq, Serialize, Deserialize)]
pub struct OrderCancelReject {
pub sending_time: DateTime<Utc>,
pub ord_status: Option<OrderStatus>,
pub cxl_rej_reason: Option<i32>,
pub cxl_rej_response_to: Option<char>,
pub text: Option<String>,
pub cl_ord_id: Option<String>,
pub orig_cl_ord_id: Option<String>,
pub deribit_label: Option<String>,
}
impl OrderCancelReject {
pub fn new(
ord_status: Option<OrderStatus>,
cxl_rej_reason: Option<i32>,
text: Option<String>,
) -> Self {
Self {
sending_time: Utc::now(),
ord_status,
cxl_rej_reason,
cxl_rej_response_to: None,
text,
cl_ord_id: None,
orig_cl_ord_id: None,
deribit_label: None,
}
}
pub fn with_cl_ord_id(mut self, cl_ord_id: String) -> Self {
self.cl_ord_id = Some(cl_ord_id);
self
}
pub fn with_orig_cl_ord_id(mut self, orig_cl_ord_id: String) -> Self {
self.orig_cl_ord_id = Some(orig_cl_ord_id);
self
}
pub fn with_deribit_label(mut self, deribit_label: String) -> Self {
self.deribit_label = Some(deribit_label);
self
}
pub fn with_cxl_rej_response_to(mut self, response_to: char) -> Self {
self.cxl_rej_response_to = Some(response_to);
self
}
pub fn to_fix_message(
&self,
sender_comp_id: &str,
target_comp_id: &str,
msg_seq_num: u32,
) -> DeribitFixResult<String> {
let mut builder = MessageBuilder::new()
.msg_type(MsgType::OrderCancelReject)
.sender_comp_id(sender_comp_id.to_string())
.target_comp_id(target_comp_id.to_string())
.msg_seq_num(msg_seq_num)
.sending_time(self.sending_time);
builder = builder.field(
52,
self.sending_time.format("%Y%m%d-%H:%M:%S%.3f").to_string(),
);
if let Some(ord_status) = &self.ord_status {
builder = builder.field(39, char::from(*ord_status).to_string());
}
if let Some(cxl_rej_reason) = &self.cxl_rej_reason {
builder = builder.field(102, cxl_rej_reason.to_string());
}
if let Some(cxl_rej_response_to) = &self.cxl_rej_response_to {
builder = builder.field(434, cxl_rej_response_to.to_string());
}
if let Some(text) = &self.text {
builder = builder.field(58, text.clone());
}
if let Some(cl_ord_id) = &self.cl_ord_id {
builder = builder.field(11, cl_ord_id.clone());
}
if let Some(orig_cl_ord_id) = &self.orig_cl_ord_id {
builder = builder.field(41, orig_cl_ord_id.clone());
}
if let Some(deribit_label) = &self.deribit_label {
builder = builder.field(100010, deribit_label.clone());
}
Ok(builder.build()?.to_string())
}
}
impl_json_display!(OrderCancelReject);
impl_json_debug_pretty!(OrderCancelReject);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_order_cancel_reject_creation() {
let reject = OrderCancelReject::new(
Some(OrderStatus::New),
Some(5), Some("Order not found".to_string()),
);
assert_eq!(reject.ord_status, Some(OrderStatus::New));
assert_eq!(reject.cxl_rej_reason, Some(5));
assert_eq!(reject.text, Some("Order not found".to_string()));
assert!(reject.sending_time <= Utc::now());
}
#[test]
fn test_order_cancel_reject_with_cl_ord_id() {
let reject = OrderCancelReject::new(
Some(OrderStatus::Cancelled),
Some(0), None,
)
.with_cl_ord_id("ORDER123".to_string());
assert_eq!(reject.cl_ord_id, Some("ORDER123".to_string()));
}
#[test]
fn test_order_cancel_reject_with_orig_cl_ord_id() {
let reject = OrderCancelReject::new(
Some(OrderStatus::New),
Some(1), Some("Invalid symbol".to_string()),
)
.with_orig_cl_ord_id("ORIG456".to_string());
assert_eq!(reject.orig_cl_ord_id, Some("ORIG456".to_string()));
}
#[test]
fn test_order_cancel_reject_with_deribit_label() {
let reject = OrderCancelReject::new(
Some(OrderStatus::PartiallyFilled),
Some(6), None,
)
.with_deribit_label("my-order".to_string());
assert_eq!(reject.deribit_label, Some("my-order".to_string()));
}
#[test]
fn test_order_cancel_reject_to_fix_message() {
let reject = OrderCancelReject::new(
Some(OrderStatus::New),
Some(5), Some("Order not found".to_string()),
)
.with_cl_ord_id("ORDER123".to_string());
let fix_message = reject.to_fix_message("DERIBITSERVER", "CLIENT", 1);
assert!(fix_message.is_ok());
let message = fix_message.unwrap();
assert!(message.contains("35=9")); assert!(message.contains("39=0")); assert!(message.contains("102=5")); assert!(message.contains("58=Order not found")); assert!(message.contains("11=ORDER123")); }
#[test]
fn test_order_cancel_reject_minimal() {
let reject = OrderCancelReject::new(None, None, None);
let fix_message = reject.to_fix_message("DERIBITSERVER", "CLIENT", 1);
assert!(fix_message.is_ok());
let message = fix_message.unwrap();
assert!(message.contains("35=9")); assert!(message.contains("52=")); }
}