Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 3c16fd1

Browse files
committedApr 30, 2024
Initial commit
0 parents  commit 3c16fd1

10 files changed

+160
-0
lines changed
 

‎.gitignore

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Generated by Cargo
2+
# will have compiled files and executables
3+
debug/
4+
target/
5+
6+
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
7+
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
8+
Cargo.lock
9+
10+
# These are backup files generated by rustfmt
11+
**/*.rs.bk
12+
13+
# MSVC Windows builds of rustc generate these, which store debugging information
14+
*.pdb

‎Cargo.lock

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Cargo.toml

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[package]
2+
name = "tax_ids"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]

‎LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2024 Jonas Molander
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

‎README.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# tax-ids

‎src/errors.rs

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
use std::fmt;
2+
3+
#[derive(Debug)]
4+
pub struct ValidationError {
5+
pub message: String,
6+
}
7+
8+
impl ValidationError {
9+
pub fn new(message: &str) -> ValidationError {
10+
ValidationError {
11+
message: message.to_string(),
12+
}
13+
}
14+
}
15+
16+
impl fmt::Display for ValidationError {
17+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
18+
write!(f, "{}", self.message)
19+
}
20+
}
21+
22+
impl std::error::Error for ValidationError {}

‎src/eu_vat.rs

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
use crate::tax_id::TaxIdType;
2+
3+
pub struct EUVat;
4+
5+
impl TaxIdType for EUVat {
6+
fn name(&self) -> &'static str {
7+
"eu_vat"
8+
}
9+
}

‎src/gb_vat.rs

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
use crate::tax_id::TaxIdType;
2+
3+
pub struct GBVat;
4+
5+
impl TaxIdType for GBVat {
6+
fn name(&self) -> &'static str {
7+
"gb_vat"
8+
}
9+
}

‎src/lib.rs

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
mod tax_id;
2+
mod eu_vat;
3+
mod gb_vat;
4+
mod errors;

‎src/tax_id.rs

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
use crate::eu_vat::EUVat;
2+
use crate::gb_vat::GBVat;
3+
use crate::errors::ValidationError;
4+
5+
pub trait TaxIdType {
6+
fn name(&self) -> &'static str;
7+
}
8+
9+
struct TaxId {
10+
value: String,
11+
country_code: String,
12+
local_value: String,
13+
id_type: &'static str,
14+
}
15+
16+
impl TaxId {
17+
pub fn new(value: &str) -> Result<TaxId, ValidationError> {
18+
let country_code = &value[0..2];
19+
let local_value = &value[2..];
20+
let id_type: Box<dyn TaxIdType> = match country_code {
21+
"SE" => Box::new(EUVat),
22+
"GB" => Box::new(GBVat),
23+
_ => return Err(ValidationError::new("Unknown country code"))
24+
};
25+
26+
Ok(TaxId {
27+
id_type: id_type.name(),
28+
value: value.to_string(),
29+
country_code: country_code.to_string(),
30+
local_value: local_value.to_string(),
31+
})
32+
}
33+
34+
pub fn value(&self) -> &str { &self.value }
35+
pub fn country_code(&self) -> &str { &self.country_code }
36+
pub fn local_value(&self) -> &str { &self.local_value }
37+
pub fn id_type(&self) -> &str { &self.id_type }
38+
}
39+
40+
#[cfg(test)]
41+
mod tests {
42+
use super::*;
43+
44+
#[test]
45+
fn test_new_eu_vat() {
46+
let tax_id= TaxId::new("SE1234567890").unwrap();
47+
assert_eq!(tax_id.value(), "SE1234567890");
48+
assert_eq!(tax_id.country_code(), "SE");
49+
assert_eq!(tax_id.local_value(), "1234567890");
50+
assert_eq!(tax_id.id_type(), "eu_vat");
51+
}
52+
53+
#[test]
54+
fn test_new_gb_vat() {
55+
let tax_id = TaxId::new("GB123456789").unwrap();
56+
assert_eq!(tax_id.value(), "GB123456789");
57+
assert_eq!(tax_id.country_code(), "GB");
58+
assert_eq!(tax_id.local_value(), "123456789");
59+
assert_eq!(tax_id.id_type(), "gb_vat");
60+
}
61+
62+
#[test]
63+
#[should_panic(expected = "Unknown country code")]
64+
fn test_new_unknown_country_code() {
65+
let _ = TaxId::new("XX123456789").unwrap();
66+
}
67+
}

0 commit comments

Comments
 (0)
Please sign in to comment.