1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
//! Integration mapping domain models
//!
//! An integration mapping translates a value from an external system into the
//! internal canonical value (and vice-versa) for a given integration and
//! mapping group — e.g. mapping a Shopify carrier name to a Trackstar carrier
//! enum, or an external order status to an internal one. Mappings are unique on
//! `(integration, mapping_group, field_name, external_value)`.
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use stateset_primitives::IntegrationMappingId;
/// A single external→internal value mapping for an integration.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IntegrationMapping {
/// Unique mapping ID.
pub id: IntegrationMappingId,
/// Backing integration (e.g. `shopify`, `trackstar`).
pub integration: String,
/// Logical mapping group (e.g. `carrier`, `order_status`, `payment_method`).
pub mapping_group: String,
/// Field name within the group (e.g. `carrier_code`).
pub field_name: String,
/// The value as seen in the external system.
pub external_value: String,
/// The canonical internal value it maps to.
pub internal_value: String,
/// Whether the mapping is active.
pub is_active: bool,
/// When the mapping was created.
pub created_at: DateTime<Utc>,
/// When the mapping was last updated.
pub updated_at: DateTime<Utc>,
}
/// Input for creating an integration mapping.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateIntegrationMapping {
/// Backing integration.
pub integration: String,
/// Mapping group.
pub mapping_group: String,
/// Field name.
pub field_name: String,
/// External value.
pub external_value: String,
/// Internal value.
pub internal_value: String,
}
/// Input for updating an integration mapping (partial).
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct UpdateIntegrationMapping {
/// Updated internal value.
pub internal_value: Option<String>,
/// Updated active state.
pub is_active: Option<bool>,
}
/// Filter for listing integration mappings.
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct IntegrationMappingFilter {
/// Filter by integration.
pub integration: Option<String>,
/// Filter by mapping group.
pub mapping_group: Option<String>,
/// Filter by field name.
pub field_name: Option<String>,
/// Filter by active state.
pub is_active: Option<bool>,
/// Maximum results.
pub limit: Option<u32>,
/// Offset for pagination.
pub offset: Option<u32>,
}
/// A lookup key for resolving a mapping.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MappingLookup {
/// Integration.
pub integration: String,
/// Mapping group.
pub mapping_group: String,
/// Field name.
pub field_name: String,
/// External value to resolve.
pub external_value: String,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn create_input_round_trips_via_serde() {
let input = CreateIntegrationMapping {
integration: "shopify".into(),
mapping_group: "carrier".into(),
field_name: "carrier_code".into(),
external_value: "USPS Ground".into(),
internal_value: "usps".into(),
};
let json = serde_json::to_string(&input).unwrap();
let back: CreateIntegrationMapping = serde_json::from_str(&json).unwrap();
assert_eq!(back.external_value, "USPS Ground");
assert_eq!(back.internal_value, "usps");
}
#[test]
fn update_defaults_are_none() {
let u = UpdateIntegrationMapping::default();
assert!(u.internal_value.is_none());
assert!(u.is_active.is_none());
}
#[test]
fn filter_defaults_are_none() {
let f = IntegrationMappingFilter::default();
assert!(f.integration.is_none());
assert!(f.mapping_group.is_none());
assert!(f.limit.is_none());
}
}