use crate::prelude::*;
pub type Result<T, E = Error> = std::result::Result<T, E>;
#[derive(Clone, Debug, ThisError, PartialEq)]
pub enum Error {
#[error("Records off must not contain offset period: {offset_period}")]
RecordsOffMustNotContainOffsetPeriod { offset_period: String },
#[error("Start period ('{start}') is after end period ('{end}')")]
StartPeriodAfterEndPeriod { start: String, end: String },
#[error("Invalid Period, bad value: {bad_value}")]
InvalidPeriod { bad_value: String },
#[error("Period is not YearAndMonth")]
PeriodIsNotYearAndMonth,
#[error("Period is not YearMonthAndFortnight")]
PeriodIsNotYearMonthAndFortnight,
#[error(
"Invalid granularity for time off: '{free_granularity}', expected: '{service_fees_granularity}', use the same time unit for time off as you specified in service fees. View it with `klirr data dump` command."
)]
InvalidGranularityForTimeOff {
free_granularity: Granularity,
service_fees_granularity: Granularity,
},
#[error(
"Granularity too coarse '{granularity}', max is: '{max_granularity}', for period: '{target_period}'"
)]
GranularityTooCoarse {
granularity: Granularity,
max_granularity: Granularity,
target_period: String,
},
#[error("Cannot invoice for month when cadence is bi-weekly")]
CannotInvoiceForMonthWhenCadenceIsBiWeekly,
#[error("Cannot expense for month when cadence is bi-weekly")]
CannotExpenseForMonthWhenCadenceIsBiWeekly,
#[error("Cannot expense for fortnight when cadence is monthly")]
CannotExpenseForFortnightWhenCadenceIsMonthly,
#[error("Passwords do not match")]
PasswordDoesNotMatch,
#[error(
"Email password is too short, expected at least {min_length} characters, but found {actual_length}"
)]
EmailPasswordTooShort {
min_length: usize,
actual_length: usize,
},
#[error("Failed to parse email atom template: {underlying}")]
EmailAtomTemplateError { underlying: String },
#[error("Invalid email address for: {role}, because: {underlying}")]
InvalidEmailAddress { role: String, underlying: String },
#[error("Invalid name for email for: {role}, because: {underlying}")]
InvalidNameForEmail { role: String, underlying: String },
#[error("Invalid password for email {purpose}, because: {underlying}")]
InvalidPasswordForEmail { purpose: String, underlying: String },
#[error("Recipient addresses cannot be empty")]
RecipientAddressesCannotBeEmpty,
#[error("Failed to parse SMTP Server, because: {underlying}")]
InvalidSmtpServer { underlying: String },
#[error("Failed to parse string into a valid UTF-8 string")]
InvalidUtf8,
#[error("Failed to decrypt data with AES")]
AESDecryptionFailed,
#[error(
"Invalid AES bytes, expected at least {expected_at_least} bytes, but found {found} bytes"
)]
InvalidAESBytesTooShort {
expected_at_least: usize,
found: usize,
},
#[error("Failed to create SMTP transport, because: {underlying}")]
CreateSmtpTransportError { underlying: String },
#[error("Failed to create email, because: {underlying}")]
CreateEmailError { underlying: String },
#[error("Failed to add attachments to the email, because: {underlying}")]
AddAttachmentsError {
underlying: String,
},
#[error("Failed to send email, because: {underlying}")]
SendEmailError { underlying: String },
#[error("Failed to convert to f64 from Decimal, because: {value}")]
InvalidDecimalToF64Conversion { value: String },
#[error("Failed to convert f64 to Decimal, because: {value}")]
InvalidDecimalFromF64Conversion { value: f64 },
#[error("Failed to load font with family name: '{family_name}'")]
FailedToLoadFont { family_name: String },
#[error("Failed to parse f64 from string: {bad_value}, reason: {reason}")]
InvalidF64String { bad_value: String, reason: String },
#[error("Failed to write data to disk, because: {underlying}")]
FailedToWriteDataToDisk { underlying: String },
#[error("Failed to RON serialize data, because: {underlying}")]
FailedToRonSerializeData {
type_name: String,
underlying: String,
},
#[error("Failed to build CompanyInformation from Terminal UI input, because: {reason}")]
InvalidCompanyInformation { reason: String },
#[error("Failed to parse invoice number from string: {invalid_string}")]
InvalidInvoiceNumberString { invalid_string: String },
#[error("Failed to build InvoiceInfo from Terminal UI input, because: {reason}")]
InvalidInvoiceInfo { reason: String },
#[error("Failed to build PaymentInfo from Terminal UI input, because: {reason}")]
InvalidPaymentInfo { reason: String },
#[error("Failed to build ServiceFees from Terminal UI input, because: {reason}")]
InvalidServiceFees { reason: String },
#[error(
"Offset period must not be in the record of periods off: {offset_period}, period kind: {period_kind}"
)]
OffsetPeriodMustNotBeInRecordOfPeriodsOff {
offset_period: String,
period_kind: String,
},
#[error("Specified output path does not exist: {path}")]
SpecifiedOutputPathDoesNotExist { path: String },
#[error("Failed to create output directory: {underlying}")]
FailedToCreateOutputDirectory { underlying: String },
#[error(
"Target period {target_period} must have expenses, but it does not. Fill
in the `input/data/expenses.json` file with expenses for this period."
)]
TargetPeriodMustHaveExpenses { target_period: String },
#[error("Failed to parse year: {invalid_string}")]
FailedToParseYear { invalid_string: String },
#[error("Failed to load file: {path}, underlying: {underlying}")]
FileNotFound { path: String, underlying: String },
#[error("Failed to deserialize {type_name}, because: {error}")]
Deserialize { type_name: String, error: String },
#[error("Invalid day from String: {invalid_string}, reason: {reason}")]
InvalidDayFromString {
invalid_string: String,
reason: String,
},
#[error("Invalid YearAndMonth, underlying: {underlying}")]
InvalidYearAndMonth { underlying: String },
#[error("Invalid date, underlying: {underlying}")]
InvalidDate { underlying: String },
#[error("Invalid day: {day}, reason: {reason}")]
InvalidDay { day: i32, reason: String },
#[error("Invalid month: {month}, reason: {reason}")]
InvalidMonth { month: i32, reason: String },
#[error("Failed to parse Month: {invalid_string}")]
FailedToParseMonth { invalid_string: String },
#[error("Failed to parse expense item from: '{invalid_string}': {reason}")]
InvalidExpenseItem {
invalid_string: String,
reason: String,
},
#[error("Target period {target_period} is in the record of periods off, but it must not be.")]
TargetPeriodMustNotBeInRecordOfPeriodsOff { target_period: String },
#[error("Failed to PaymentTerms NetDays from string: {invalid_string}")]
FailedToParsePaymentTermsNetDays { invalid_string: String },
#[error("Failed to find the localization file for language: {language}")]
L18nNotFound {
language: Language,
},
#[error("Invalid hex color format: {invalid_string}")]
InvalidHexColor { invalid_string: String },
#[error("Failed to parse date, because: {underlying}")]
FailedToParseDate { underlying: String },
#[error("Found no exchange rate for {target} based on {base}")]
FoundNoExchangeRate {
target: Currency,
base: Currency,
},
#[error("Failed to load Typst source, because: {underlying}")]
LoadSource { underlying: String },
#[error("Failed to compile Typst source, because: {underlying}")]
BuildPdf { underlying: String },
#[error("Failed to export PagedDocument to PDF, because: {underlying}")]
ExportDocumentToPdf { underlying: String },
#[error("Failed to save PDF, because: {underlying}")]
SavePdf { underlying: String },
#[error("Failed fetch exchange rate from API, because: {underlying}")]
NetworkError { underlying: String },
#[error("Failed to parse exchange rate response, because: {underlying}")]
ParseError { underlying: String },
}