Helper Utilities
This module provides reusable utility functions used across the application.
The helper functions cover:
- Datetime formatting
- String normalization
- Empty value validation
- Email validation
- Name validation
- Price validation
- Sequence generation
- Module prefix formatting
File Structure
Module Dependencies
use chrono::{DateTime, Local};
use regex::Regex;
use crate::utils::Responses;
use axum::{http::StatusCode, response::{AppendHeaders, IntoResponse, Response}, Json};
use serde::Serializer;
use serde_json::json;
Helper Function Overview
| Function | Purpose |
|---|---|
time_now_modif | Get current local datetime |
format_datetime | Serialize datetime into formatted string |
convert_to_normalize_lower | Normalize string to lowercase |
is_empty | Check empty string |
not_empty | Check non-empty string |
is_valid_name | Validate name format |
is_valid_email | Validate email format |
is_valid_price | Validate numeric price |
sequence_number | Generate padded sequence number |
prefix_module | Generate prefixed document code |
splits_prefix_module | Validate module prefix |
Utility Architecture
Current Datetime Helper
Source Code
//format : 2026-05-07 14:30:00
#[allow(dead_code)]
pub fn time_now_modif() -> DateTime<Local> {
Local::now()
}
Explanation
Returns the current local datetime using Chrono.
Return Type
DateTime<Local>
Represents timezone-aware local datetime.
Datetime Formatter
Source Code
pub fn format_datetime<S>(
date: &Option<DateTime<Local>>,
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match date {
Some(dt) => serializer.serialize_str(
&dt.format("%Y-%m-%d %H:%M:%S").to_string()
),
None => serializer.serialize_none(),
}
}
Datetime Serialization Flow
Datetime Format
2026-05-07 14:30:00
String Normalization
Source Code
// trim + lower
#[allow(dead_code)]
pub fn convert_to_normalize_lower(value:&str)->String{
value.trim().to_lowercase()
}
Explanation
Performs:
- Whitespace trimming
- Lowercase conversion
Example
| Input | Output |
|---|---|
" ADMIN " | "admin" |
Empty String Validation
is_empty
pub fn is_empty(value:&str)->bool{
value.trim().is_empty()
}
Explanation
Checks whether a string is empty after trimming whitespace.
Example
| Input | Result |
|---|---|
" " | true |
"hello" | false |
Non-Empty Validation
Source Code
/// Check not empty string
#[allow(dead_code)]
pub fn not_empty(value: &str) -> bool {
!value.trim().is_empty()
}
Explanation
Returns the inverse result of is_empty.
Name Validation
Source Code
/// Valid name:
/// a-z A-Z 0-9 . space
#[allow(dead_code)]
pub fn is_valid_name(name: &str) -> bool {
let regex = Regex::new(r"^[a-zA-Z0-9.\s]+$").unwrap();
regex.is_match(name)
}
Allowed Characters
| Character Type | Allowed |
|---|---|
| Uppercase letters | Yes |
| Lowercase letters | Yes |
| Numbers | Yes |
Dot (.) | Yes |
| Space | Yes |
Regex Pattern
^[a-zA-Z0-9.\s]+$
Validation Examples
| Input | Result |
|---|---|
"John Doe" | true |
"User.01" | true |
"Admin@Root" | false |
Email Validation
Source Code
/// Validate email
pub fn is_valid_email(email: &str) -> bool {
let regex =
Regex::new(r"^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$").unwrap();
regex.is_match(email)
}
Email Validation Flow
Supported Email Format
Examples:
user@example.com
admin.system@test.org
Price Validation
Source Code
/// Validate price
/// only number + dot + space
#[allow(dead_code)]
pub fn is_valid_price(price: &str) -> bool {
let regex = Regex::new(r"^[0-9.\s]+$").unwrap();
regex.is_match(price)
}
Allowed Characters
| Character | Allowed |
|---|---|
| Numbers | Yes |
Dot (.) | Yes |
| Space | Yes |
Example
| Input | Result |
|---|---|
"1000" | true |
"10.500" | true |
"1000USD" | false |
Sequence Number Generator
Source Code
/// Example:
/// 1 => 000001
#[allow(dead_code)]
pub fn sequence_number(n: i64) -> String {
format!("{:06}", n)
}
Sequence Format
Pads numbers into 6-digit format.
Examples
| Input | Output |
|---|---|
1 | 000001 |
25 | 000025 |
1000 | 001000 |
Prefix Module Generator
Source Code
/// Example:
/// INV-2605000001
pub fn prefix_module(code: &str, seq: i64) -> String {
let date = Local::now().format("%y%m").to_string();
format!("{}-{}{}", code, date, sequence_number(seq))
}
Prefix Format Structure
Format Example
INV-2605000001
Format Breakdown
| Segment | Description |
|---|---|
INV | Module code |
2605 | Year and month |
000001 | Sequence number |
Prefix Validation
Source Code
pub fn splits_prefix_module(code:&str, value:&str) ->bool{
value.trim().to_lowercase().starts_with(&format!("{}-",code.trim().to_lowercase()))
}
Explanation
Checks whether a value starts with a specific module prefix.
Validation Example
| Code | Value | Result |
|---|---|---|
INV | INV-2605000001 | true |
TRX | INV-2605000001 | false |
Validation Logic
Utility Design Summary
| Category | Responsibility |
|---|---|
| Datetime Utility | Current time and formatting |
| String Utility | Normalize and trim values |
| Validation Utility | Validate names, emails, prices |
| Sequence Utility | Generate formatted identifiers |
| Prefix Utility | Validate module codes |
Design Characteristics
Lightweight
Functions are reusable and independent.
Stateless
No shared mutable state is used.
Reusable
Can be reused across:
- Services
- Middleware
- Validation layers
- Response formatting
- Database modules
Common Use Cases
| Feature | Helper Function |
|---|---|
| Generate invoice number | prefix_module |
| Validate email input | is_valid_email |
| Normalize user input | convert_to_normalize_lower |
| Serialize datetime response | format_datetime |
| Validate empty form field | is_empty |
| Validate product price | is_valid_price |