Skip to main content

datasynth_core/country/
schema.rs

1//! Country pack schema types.
2//!
3//! Defines the `CountryPack` struct and all sub-structs that map to the
4//! country-pack JSON schema (spec §3.1–§3.16). Every field uses `#[serde(default)]`
5//! so that partial packs (e.g. `_default.json`) deserialize cleanly.
6
7use serde::{Deserialize, Serialize};
8
9// ---------------------------------------------------------------------------
10// Top-level
11// ---------------------------------------------------------------------------
12
13/// A complete country pack loaded from JSON.
14#[derive(Debug, Clone, Serialize, Deserialize, Default)]
15pub struct CountryPack {
16    /// Schema version (e.g. "1.0").
17    #[serde(default)]
18    pub schema_version: String,
19    /// ISO 3166-1 alpha-2 country code, or "_DEFAULT".
20    #[serde(default)]
21    pub country_code: String,
22    /// Human-readable country name.
23    #[serde(default)]
24    pub country_name: String,
25    /// Region grouping: AMERICAS, EMEA, APAC.
26    #[serde(default)]
27    pub region: String,
28
29    #[serde(default)]
30    pub locale: LocaleConfig,
31    #[serde(default)]
32    pub names: NamesConfig,
33    #[serde(default)]
34    pub holidays: HolidaysConfig,
35    #[serde(default)]
36    pub tax: CountryTaxConfig,
37    #[serde(default)]
38    pub address: AddressConfig,
39    #[serde(default)]
40    pub phone: PhoneConfig,
41    #[serde(default)]
42    pub banking: BankingCountryConfig,
43    #[serde(default)]
44    pub business_rules: BusinessRulesConfig,
45    #[serde(default)]
46    pub legal_entities: LegalEntitiesConfig,
47    #[serde(default)]
48    pub accounting: AccountingCountryConfig,
49    #[serde(default)]
50    pub payroll: PayrollCountryConfig,
51    #[serde(default)]
52    pub vendor_templates: EntityTemplatesConfig,
53    #[serde(default)]
54    pub customer_templates: EntityTemplatesConfig,
55    #[serde(default)]
56    pub material_templates: MaterialTemplatesConfig,
57    #[serde(default)]
58    pub document_texts: DocumentTextsConfig,
59}
60
61// ---------------------------------------------------------------------------
62// §3.2  Locale
63// ---------------------------------------------------------------------------
64
65#[derive(Debug, Clone, Serialize, Deserialize, Default)]
66pub struct LocaleConfig {
67    #[serde(default)]
68    pub language_code: String,
69    #[serde(default)]
70    pub language_name: String,
71    #[serde(default)]
72    pub default_currency: String,
73    #[serde(default)]
74    pub currency_symbol: String,
75    #[serde(default = "default_currency_decimal_places")]
76    pub currency_decimal_places: u8,
77    #[serde(default)]
78    pub number_format: NumberFormatConfig,
79    #[serde(default)]
80    pub date_format: DateFormatConfig,
81    #[serde(default)]
82    pub default_timezone: String,
83    #[serde(default)]
84    pub weekend_days: Vec<String>,
85    #[serde(default)]
86    pub fiscal_year: FiscalYearConfig,
87}
88
89fn default_currency_decimal_places() -> u8 {
90    2
91}
92
93#[derive(Debug, Clone, Serialize, Deserialize, Default)]
94pub struct NumberFormatConfig {
95    #[serde(default = "default_decimal_separator")]
96    pub decimal_separator: String,
97    #[serde(default = "default_thousands_separator")]
98    pub thousands_separator: String,
99    #[serde(default)]
100    pub grouping: Vec<u8>,
101}
102
103fn default_decimal_separator() -> String {
104    ".".to_string()
105}
106
107fn default_thousands_separator() -> String {
108    ",".to_string()
109}
110
111#[derive(Debug, Clone, Serialize, Deserialize, Default)]
112pub struct DateFormatConfig {
113    #[serde(default)]
114    pub short: String,
115    #[serde(default)]
116    pub long: String,
117    #[serde(default)]
118    pub iso: String,
119}
120
121#[derive(Debug, Clone, Serialize, Deserialize)]
122pub struct FiscalYearConfig {
123    #[serde(default = "default_one")]
124    pub start_month: u32,
125    #[serde(default = "default_one")]
126    pub start_day: u32,
127    #[serde(default = "default_fiscal_variant_str")]
128    pub variant: String,
129}
130
131impl Default for FiscalYearConfig {
132    fn default() -> Self {
133        Self {
134            start_month: 1,
135            start_day: 1,
136            variant: "calendar".to_string(),
137        }
138    }
139}
140
141fn default_one() -> u32 {
142    1
143}
144
145fn default_fiscal_variant_str() -> String {
146    "calendar".to_string()
147}
148
149// ---------------------------------------------------------------------------
150// §3.3  Names
151// ---------------------------------------------------------------------------
152
153#[derive(Debug, Clone, Serialize, Deserialize, Default)]
154pub struct NamesConfig {
155    #[serde(default)]
156    pub cultures: Vec<CultureConfig>,
157    #[serde(default)]
158    pub email_domains: Vec<String>,
159    #[serde(default)]
160    pub username_patterns: Vec<String>,
161}
162
163#[derive(Debug, Clone, Serialize, Deserialize, Default)]
164pub struct CultureConfig {
165    #[serde(default)]
166    pub culture_id: String,
167    #[serde(default)]
168    pub weight: f64,
169    #[serde(default)]
170    pub male_first_names: Vec<String>,
171    #[serde(default)]
172    pub female_first_names: Vec<String>,
173    #[serde(default)]
174    pub last_names: Vec<String>,
175    #[serde(default = "default_western")]
176    pub name_order: String,
177    #[serde(default)]
178    pub titles: TitleConfig,
179    #[serde(default)]
180    pub academic_titles: Vec<String>,
181}
182
183fn default_western() -> String {
184    "western".to_string()
185}
186
187#[derive(Debug, Clone, Serialize, Deserialize, Default)]
188pub struct TitleConfig {
189    #[serde(default)]
190    pub male: Vec<String>,
191    #[serde(default)]
192    pub female: Vec<String>,
193}
194
195// ---------------------------------------------------------------------------
196// §3.4  Holidays
197// ---------------------------------------------------------------------------
198
199#[derive(Debug, Clone, Serialize, Deserialize, Default)]
200pub struct HolidaysConfig {
201    #[serde(default = "default_gregorian")]
202    pub calendar_type: String,
203    #[serde(default)]
204    pub fixed: Vec<FixedHoliday>,
205    #[serde(default)]
206    pub easter_relative: Vec<EasterRelativeHoliday>,
207    #[serde(default)]
208    pub nth_weekday: Vec<NthWeekdayHoliday>,
209    #[serde(default)]
210    pub last_weekday: Vec<LastWeekdayHoliday>,
211    #[serde(default)]
212    pub lunar: Vec<LunarHoliday>,
213    #[serde(default)]
214    pub regional_holidays: RegionalHolidaysConfig,
215    #[serde(default)]
216    pub holiday_seasons: Vec<HolidaySeasonConfig>,
217}
218
219fn default_gregorian() -> String {
220    "gregorian".to_string()
221}
222
223#[derive(Debug, Clone, Serialize, Deserialize, Default)]
224pub struct FixedHoliday {
225    #[serde(default)]
226    pub name: String,
227    #[serde(default)]
228    pub name_en: String,
229    #[serde(default)]
230    pub month: u32,
231    #[serde(default)]
232    pub day: u32,
233    #[serde(default = "default_holiday_activity")]
234    pub activity_multiplier: f64,
235    #[serde(default)]
236    pub observe_weekend_rule: bool,
237}
238
239fn default_holiday_activity() -> f64 {
240    0.05
241}
242
243#[derive(Debug, Clone, Serialize, Deserialize, Default)]
244pub struct EasterRelativeHoliday {
245    #[serde(default)]
246    pub name: String,
247    #[serde(default)]
248    pub name_en: String,
249    #[serde(default)]
250    pub offset_days: i32,
251    #[serde(default = "default_holiday_activity")]
252    pub activity_multiplier: f64,
253}
254
255/// "Nth weekday of month" holiday (e.g. 3rd Monday of January = MLK Day).
256#[derive(Debug, Clone, Serialize, Deserialize, Default)]
257pub struct NthWeekdayHoliday {
258    #[serde(default)]
259    pub name: String,
260    #[serde(default)]
261    pub name_en: String,
262    /// 1-12
263    #[serde(default)]
264    pub month: u32,
265    /// Day of week: "monday", "tuesday", ..., "sunday"
266    #[serde(default)]
267    pub weekday: String,
268    /// 1-based occurrence (1=first, 2=second, ..., 4=fourth)
269    #[serde(default)]
270    pub occurrence: u32,
271    /// Days to add after the computed date (e.g. 1 for "day after Thanksgiving").
272    #[serde(default)]
273    pub offset_days: i32,
274    #[serde(default = "default_holiday_activity")]
275    pub activity_multiplier: f64,
276}
277
278/// "Last weekday of month" holiday (e.g. last Monday of May = Memorial Day).
279#[derive(Debug, Clone, Serialize, Deserialize, Default)]
280pub struct LastWeekdayHoliday {
281    #[serde(default)]
282    pub name: String,
283    #[serde(default)]
284    pub name_en: String,
285    /// 1-12
286    #[serde(default)]
287    pub month: u32,
288    /// Day of week: "monday", "tuesday", ..., "sunday"
289    #[serde(default)]
290    pub weekday: String,
291    #[serde(default = "default_holiday_activity")]
292    pub activity_multiplier: f64,
293}
294
295/// Lunar-calendar holiday resolved by a named algorithm at runtime.
296#[derive(Debug, Clone, Serialize, Deserialize, Default)]
297pub struct LunarHoliday {
298    #[serde(default)]
299    pub name: String,
300    #[serde(default)]
301    pub name_en: String,
302    /// Algorithm name dispatched by `lunar::resolve_lunar_holiday()`.
303    /// Examples: "chinese_new_year", "diwali", "vesak", "hari_raya_puasa",
304    /// "hari_raya_haji", "deepavali", "korean_new_year",
305    /// "korean_buddha_birthday", "chuseok"
306    #[serde(default)]
307    pub algorithm: String,
308    /// Number of consecutive holiday days (e.g. Chinese New Year = 7).
309    #[serde(default = "default_duration")]
310    pub duration_days: u32,
311    #[serde(default = "default_holiday_activity")]
312    pub activity_multiplier: f64,
313}
314
315fn default_duration() -> u32 {
316    1
317}
318
319#[derive(Debug, Clone, Serialize, Deserialize, Default)]
320pub struct RegionalHolidaysConfig {
321    #[serde(default)]
322    pub enabled: bool,
323    #[serde(default)]
324    pub regions: serde_json::Value,
325}
326
327#[derive(Debug, Clone, Serialize, Deserialize, Default)]
328pub struct HolidaySeasonConfig {
329    #[serde(default)]
330    pub name: String,
331    #[serde(default)]
332    pub name_en: String,
333    #[serde(default)]
334    pub start: MonthDay,
335    #[serde(default)]
336    pub end: MonthDay,
337    #[serde(default = "default_holiday_activity")]
338    pub activity_multiplier: f64,
339    #[serde(default)]
340    pub description: String,
341}
342
343#[derive(Debug, Clone, Serialize, Deserialize, Default)]
344pub struct MonthDay {
345    #[serde(default)]
346    pub month: u32,
347    #[serde(default)]
348    pub day: u32,
349}
350
351// ---------------------------------------------------------------------------
352// §3.5  Tax
353// ---------------------------------------------------------------------------
354
355/// Country-level tax configuration.
356/// Named `CountryTaxConfig` to avoid collision with the generator-level `TaxConfig`.
357#[derive(Debug, Clone, Serialize, Deserialize, Default)]
358pub struct CountryTaxConfig {
359    #[serde(default)]
360    pub corporate_income_tax: CorporateIncomeTaxConfig,
361    #[serde(default)]
362    pub vat: VatConfig,
363    #[serde(default)]
364    pub withholding_tax: WithholdingTaxConfig,
365    #[serde(default)]
366    pub payroll_tax: PayrollTaxBracketsConfig,
367    #[serde(default)]
368    pub transfer_pricing: TransferPricingConfig,
369    /// Sub-national tax jurisdictions (US states, German Bundesländer, etc.).
370    #[serde(default)]
371    pub subnational: Vec<SubnationalTaxConfig>,
372}
373
374#[derive(Debug, Clone, Serialize, Deserialize, Default)]
375pub struct CorporateIncomeTaxConfig {
376    #[serde(default)]
377    pub standard_rate: f64,
378    #[serde(default)]
379    pub trade_tax_rate: f64,
380    #[serde(default)]
381    pub solidarity_surcharge: f64,
382    #[serde(default)]
383    pub effective_combined_rate: f64,
384    #[serde(default)]
385    pub small_business_threshold: Option<f64>,
386}
387
388#[derive(Debug, Clone, Serialize, Deserialize, Default)]
389pub struct VatConfig {
390    #[serde(default)]
391    pub standard_rate: f64,
392    #[serde(default)]
393    pub reduced_rates: Vec<ReducedRate>,
394    #[serde(default)]
395    pub zero_rated: Vec<String>,
396    #[serde(default)]
397    pub exempt: Vec<String>,
398    #[serde(default)]
399    pub registration_threshold: Option<f64>,
400    #[serde(default)]
401    pub filing_frequency: String,
402    #[serde(default)]
403    pub reverse_charge_applicable: bool,
404}
405
406#[derive(Debug, Clone, Serialize, Deserialize, Default)]
407pub struct ReducedRate {
408    #[serde(default)]
409    pub rate: f64,
410    #[serde(default)]
411    pub label: String,
412    #[serde(default)]
413    pub applies_to: Vec<String>,
414}
415
416#[derive(Debug, Clone, Serialize, Deserialize, Default)]
417pub struct WithholdingTaxConfig {
418    #[serde(default)]
419    pub dividends_domestic: f64,
420    #[serde(default)]
421    pub dividends_foreign_default: f64,
422    #[serde(default)]
423    pub interest: f64,
424    #[serde(default)]
425    pub royalties: f64,
426    #[serde(default)]
427    pub services: f64,
428}
429
430#[derive(Debug, Clone, Serialize, Deserialize, Default)]
431pub struct PayrollTaxBracketsConfig {
432    #[serde(default)]
433    pub income_tax_brackets: Vec<TaxBracket>,
434    #[serde(default)]
435    pub social_security: serde_json::Value,
436    #[serde(default)]
437    pub church_tax_rate: f64,
438}
439
440#[derive(Debug, Clone, Serialize, Deserialize, Default)]
441pub struct TaxBracket {
442    #[serde(default)]
443    pub up_to: Option<f64>,
444    #[serde(default)]
445    pub above: Option<f64>,
446    #[serde(default)]
447    pub rate: f64,
448}
449
450#[derive(Debug, Clone, Serialize, Deserialize, Default)]
451pub struct TransferPricingConfig {
452    #[serde(default)]
453    pub documentation_required: bool,
454    #[serde(default)]
455    pub methods: Vec<String>,
456    #[serde(default)]
457    pub safe_harbor_rules: bool,
458}
459
460#[derive(Debug, Clone, Serialize, Deserialize, Default)]
461pub struct SubnationalTaxConfig {
462    #[serde(default)]
463    pub code: String,
464    #[serde(default)]
465    pub name: String,
466    #[serde(default)]
467    pub rate: f64,
468    #[serde(default)]
469    pub tax_type: String,
470}
471
472// ---------------------------------------------------------------------------
473// §3.6  Address
474// ---------------------------------------------------------------------------
475
476#[derive(Debug, Clone, Serialize, Deserialize, Default)]
477pub struct AddressConfig {
478    #[serde(default)]
479    pub format_template: String,
480    #[serde(default)]
481    pub components: AddressComponentsConfig,
482    #[serde(default)]
483    pub postal_code: PostalCodeConfig,
484    #[serde(default)]
485    pub building_number: BuildingNumberConfig,
486    #[serde(default)]
487    pub country_calling_code: String,
488}
489
490#[derive(Debug, Clone, Serialize, Deserialize, Default)]
491pub struct AddressComponentsConfig {
492    #[serde(default)]
493    pub street_names: Vec<String>,
494    #[serde(default)]
495    pub city_names: Vec<String>,
496    #[serde(default)]
497    pub state_names: Vec<String>,
498    #[serde(default)]
499    pub state_codes: Vec<String>,
500}
501
502#[derive(Debug, Clone, Serialize, Deserialize, Default)]
503pub struct PostalCodeConfig {
504    #[serde(default)]
505    pub format: String,
506    #[serde(default)]
507    pub regex: String,
508    #[serde(default)]
509    pub ranges: Vec<PostalCodeRange>,
510}
511
512#[derive(Debug, Clone, Serialize, Deserialize, Default)]
513pub struct PostalCodeRange {
514    #[serde(default)]
515    pub from: String,
516    #[serde(default)]
517    pub to: String,
518}
519
520#[derive(Debug, Clone, Serialize, Deserialize, Default)]
521pub struct BuildingNumberConfig {
522    #[serde(default)]
523    pub format: String,
524    #[serde(default)]
525    pub range: Vec<u32>,
526}
527
528// ---------------------------------------------------------------------------
529// §3.7  Phone
530// ---------------------------------------------------------------------------
531
532#[derive(Debug, Clone, Serialize, Deserialize, Default)]
533pub struct PhoneConfig {
534    #[serde(default)]
535    pub country_calling_code: String,
536    #[serde(default)]
537    pub formats: PhoneFormatsConfig,
538    #[serde(default)]
539    pub area_codes: Vec<String>,
540    #[serde(default)]
541    pub subscriber_length: SubscriberLengthConfig,
542    #[serde(default)]
543    pub display_format: String,
544}
545
546#[derive(Debug, Clone, Serialize, Deserialize, Default)]
547pub struct PhoneFormatsConfig {
548    #[serde(default)]
549    pub landline: String,
550    #[serde(default)]
551    pub mobile: String,
552    #[serde(default)]
553    pub freephone: String,
554}
555
556#[derive(Debug, Clone, Serialize, Deserialize, Default)]
557pub struct SubscriberLengthConfig {
558    #[serde(default)]
559    pub min: u32,
560    #[serde(default)]
561    pub max: u32,
562}
563
564// ---------------------------------------------------------------------------
565// §3.8  Banking
566// ---------------------------------------------------------------------------
567
568#[derive(Debug, Clone, Serialize, Deserialize, Default)]
569pub struct BankingCountryConfig {
570    #[serde(default)]
571    pub account_format: String,
572    #[serde(default)]
573    pub iban: IbanConfig,
574    #[serde(default)]
575    pub domestic_format: Option<DomesticBankFormatConfig>,
576    #[serde(default)]
577    pub bank_names: Vec<String>,
578    #[serde(default)]
579    pub swift_prefix: String,
580    #[serde(default)]
581    pub payment_systems: Vec<String>,
582    #[serde(default)]
583    pub settlement_rules: SettlementRulesConfig,
584    #[serde(default)]
585    pub kyc_requirements: KycRequirementsConfig,
586}
587
588#[derive(Debug, Clone, Serialize, Deserialize, Default)]
589pub struct IbanConfig {
590    #[serde(default)]
591    pub country_prefix: String,
592    #[serde(default)]
593    pub length: u32,
594    #[serde(default)]
595    pub bban_structure: String,
596    #[serde(default)]
597    pub check_digit_algorithm: String,
598}
599
600#[derive(Debug, Clone, Serialize, Deserialize, Default)]
601pub struct DomesticBankFormatConfig {
602    #[serde(default)]
603    pub routing_number_length: u32,
604    #[serde(default)]
605    pub account_number_length: u32,
606    #[serde(default)]
607    pub format_template: String,
608}
609
610#[derive(Debug, Clone, Serialize, Deserialize, Default)]
611pub struct SettlementRulesConfig {
612    #[serde(default)]
613    pub domestic_transfer_days: u32,
614    #[serde(default)]
615    pub international_transfer_days: u32,
616    #[serde(default)]
617    pub wire_cutoff_time: String,
618    #[serde(default)]
619    pub direct_debit_lead_days: u32,
620}
621
622#[derive(Debug, Clone, Serialize, Deserialize, Default)]
623pub struct KycRequirementsConfig {
624    #[serde(default)]
625    pub id_document_types: Vec<String>,
626    #[serde(default)]
627    pub pep_screening_required: bool,
628    #[serde(default)]
629    pub beneficial_ownership_threshold: f64,
630    #[serde(default)]
631    pub enhanced_due_diligence_triggers: Vec<String>,
632}
633
634// ---------------------------------------------------------------------------
635// §3.9  Business Rules
636// ---------------------------------------------------------------------------
637
638#[derive(Debug, Clone, Serialize, Deserialize, Default)]
639pub struct BusinessRulesConfig {
640    #[serde(default)]
641    pub invoice: InvoiceRulesConfig,
642    #[serde(default)]
643    pub payment_terms: PaymentTermsConfig,
644    #[serde(default)]
645    pub approval_thresholds: ApprovalThresholdsConfig,
646    #[serde(default)]
647    pub data_privacy: DataPrivacyConfig,
648    /// Country-level carbon intensity multiplier for spend-based Scope 3 emissions.
649    /// Defaults to 0.0 (unset); the generator treats 0.0 as 1.0.
650    #[serde(default)]
651    pub emission_country_multiplier: f64,
652}
653
654#[derive(Debug, Clone, Serialize, Deserialize, Default)]
655pub struct InvoiceRulesConfig {
656    #[serde(default)]
657    pub numbering_format: String,
658    #[serde(default)]
659    pub mandatory_fields: Vec<String>,
660    #[serde(default)]
661    pub retention_years: u32,
662    #[serde(default)]
663    pub electronic_invoice_mandatory: bool,
664    #[serde(default)]
665    pub e_invoice_format: String,
666}
667
668#[derive(Debug, Clone, Serialize, Deserialize, Default)]
669pub struct PaymentTermsConfig {
670    #[serde(default = "default_payment_days")]
671    pub default_days: u32,
672    #[serde(default)]
673    pub common_terms: Vec<u32>,
674    #[serde(default)]
675    pub early_payment_discount: EarlyPaymentDiscountConfig,
676    #[serde(default)]
677    pub late_payment_interest: LatePaymentInterestConfig,
678}
679
680fn default_payment_days() -> u32 {
681    30
682}
683
684#[derive(Debug, Clone, Serialize, Deserialize, Default)]
685pub struct EarlyPaymentDiscountConfig {
686    #[serde(default)]
687    pub common_rate: f64,
688    #[serde(default)]
689    pub common_days: u32,
690}
691
692#[derive(Debug, Clone, Serialize, Deserialize, Default)]
693pub struct LatePaymentInterestConfig {
694    #[serde(default)]
695    pub statutory_rate: f64,
696    #[serde(default)]
697    pub base_rate_reference: String,
698}
699
700#[derive(Debug, Clone, Serialize, Deserialize, Default)]
701pub struct ApprovalThresholdsConfig {
702    #[serde(default)]
703    pub currency: String,
704    #[serde(default)]
705    pub levels: Vec<ApprovalLevel>,
706}
707
708#[derive(Debug, Clone, Serialize, Deserialize, Default)]
709pub struct ApprovalLevel {
710    #[serde(default)]
711    pub up_to: Option<f64>,
712    #[serde(default)]
713    pub above: Option<f64>,
714    #[serde(default)]
715    pub approver: String,
716}
717
718#[derive(Debug, Clone, Serialize, Deserialize, Default)]
719pub struct DataPrivacyConfig {
720    #[serde(default)]
721    pub regulation: String,
722    #[serde(default)]
723    pub pseudonymization_required: bool,
724    #[serde(default)]
725    pub retention_limits: RetentionLimitsConfig,
726}
727
728#[derive(Debug, Clone, Serialize, Deserialize, Default)]
729pub struct RetentionLimitsConfig {
730    #[serde(default)]
731    pub employee_data_years: u32,
732    #[serde(default)]
733    pub financial_records_years: u32,
734    #[serde(default)]
735    pub tax_records_years: u32,
736}
737
738// ---------------------------------------------------------------------------
739// §3.10  Legal Entities
740// ---------------------------------------------------------------------------
741
742#[derive(Debug, Clone, Serialize, Deserialize, Default)]
743pub struct LegalEntitiesConfig {
744    #[serde(default)]
745    pub entity_types: Vec<EntityTypeConfig>,
746    #[serde(default)]
747    pub tax_id_format: IdFormatConfig,
748    #[serde(default)]
749    pub vat_id_format: VatIdFormatConfig,
750    #[serde(default)]
751    pub registration_authority: String,
752    #[serde(default)]
753    pub registration_format: String,
754}
755
756#[derive(Debug, Clone, Serialize, Deserialize, Default)]
757pub struct EntityTypeConfig {
758    #[serde(default)]
759    pub code: String,
760    #[serde(default)]
761    pub name: String,
762    #[serde(default)]
763    pub name_en: String,
764    #[serde(default)]
765    pub weight: f64,
766}
767
768#[derive(Debug, Clone, Serialize, Deserialize, Default)]
769pub struct IdFormatConfig {
770    #[serde(default)]
771    pub name: String,
772    #[serde(default)]
773    pub format: String,
774    #[serde(default)]
775    pub regex: String,
776}
777
778#[derive(Debug, Clone, Serialize, Deserialize, Default)]
779pub struct VatIdFormatConfig {
780    #[serde(default)]
781    pub name: String,
782    #[serde(default)]
783    pub prefix: String,
784    #[serde(default)]
785    pub format: String,
786    #[serde(default)]
787    pub regex: String,
788}
789
790// ---------------------------------------------------------------------------
791// §3.11  Accounting
792// ---------------------------------------------------------------------------
793
794#[derive(Debug, Clone, Serialize, Deserialize, Default)]
795pub struct AccountingCountryConfig {
796    #[serde(default)]
797    pub framework: String,
798    #[serde(default)]
799    pub secondary_framework: Option<String>,
800    #[serde(default)]
801    pub local_gaap_name: String,
802    #[serde(default)]
803    pub chart_of_accounts: ChartOfAccountsCountryConfig,
804    #[serde(default)]
805    pub audit_framework: String,
806    #[serde(default)]
807    pub regulatory: RegulatoryConfig,
808}
809
810#[derive(Debug, Clone, Serialize, Deserialize, Default)]
811pub struct ChartOfAccountsCountryConfig {
812    #[serde(default)]
813    pub standard: String,
814    #[serde(default)]
815    pub numbering_length: u32,
816    #[serde(default)]
817    pub account_ranges: serde_json::Value,
818}
819
820#[derive(Debug, Clone, Serialize, Deserialize, Default)]
821pub struct RegulatoryConfig {
822    #[serde(default)]
823    pub sox_applicable: bool,
824    #[serde(default)]
825    pub local_regulations: Vec<String>,
826    #[serde(default)]
827    pub filing_requirements: Vec<FilingRequirement>,
828}
829
830#[derive(Debug, Clone, Serialize, Deserialize, Default)]
831pub struct FilingRequirement {
832    #[serde(default)]
833    pub name: String,
834    #[serde(default)]
835    pub name_en: String,
836    #[serde(default)]
837    pub deadline_months_after_ye: u32,
838}
839
840// ---------------------------------------------------------------------------
841// §3.12  Payroll
842// ---------------------------------------------------------------------------
843
844#[derive(Debug, Clone, Serialize, Deserialize, Default)]
845pub struct PayrollCountryConfig {
846    #[serde(default)]
847    pub pay_frequency: String,
848    #[serde(default)]
849    pub currency: String,
850    #[serde(default)]
851    pub statutory_deductions: Vec<PayrollDeduction>,
852    #[serde(default)]
853    pub employer_contributions: Vec<PayrollDeduction>,
854    #[serde(default)]
855    pub minimum_wage: MinimumWageConfig,
856    #[serde(default)]
857    pub working_hours: WorkingHoursConfig,
858    #[serde(default)]
859    pub thirteenth_month: bool,
860    #[serde(default)]
861    pub severance: SeveranceConfig,
862}
863
864#[derive(Debug, Clone, Serialize, Deserialize, Default)]
865pub struct PayrollDeduction {
866    #[serde(default)]
867    pub code: String,
868    #[serde(default)]
869    pub name: String,
870    #[serde(default)]
871    pub name_en: String,
872    /// "percentage" | "progressive" | "fixed"
873    #[serde(default)]
874    pub deduction_type: String,
875    #[serde(rename = "type", default)]
876    pub type_field: String,
877    #[serde(default)]
878    pub rate: f64,
879    #[serde(default)]
880    pub optional: bool,
881}
882
883#[derive(Debug, Clone, Serialize, Deserialize, Default)]
884pub struct MinimumWageConfig {
885    #[serde(default)]
886    pub hourly: f64,
887    #[serde(default)]
888    pub currency: String,
889    #[serde(default)]
890    pub effective_date: String,
891}
892
893#[derive(Debug, Clone, Serialize, Deserialize, Default)]
894pub struct WorkingHoursConfig {
895    #[serde(default = "default_weekly_hours")]
896    pub standard_weekly: f64,
897    #[serde(default)]
898    pub max_daily: f64,
899    #[serde(default)]
900    pub statutory_annual_leave_days: u32,
901    #[serde(default)]
902    pub common_annual_leave_days: u32,
903}
904
905fn default_weekly_hours() -> f64 {
906    40.0
907}
908
909#[derive(Debug, Clone, Serialize, Deserialize, Default)]
910pub struct SeveranceConfig {
911    #[serde(default)]
912    pub statutory: bool,
913    #[serde(default)]
914    pub formula: String,
915}
916
917// ---------------------------------------------------------------------------
918// §3.13 / §3.14  Entity Templates (vendor + customer share the same shape)
919// ---------------------------------------------------------------------------
920
921#[derive(Debug, Clone, Serialize, Deserialize, Default)]
922pub struct EntityTemplatesConfig {
923    #[serde(default)]
924    pub name_patterns: Vec<String>,
925    #[serde(default)]
926    pub industry_words: serde_json::Value,
927}
928
929// ---------------------------------------------------------------------------
930// §3.15  Material Templates
931// ---------------------------------------------------------------------------
932
933#[derive(Debug, Clone, Serialize, Deserialize, Default)]
934pub struct MaterialTemplatesConfig {
935    #[serde(default)]
936    pub categories: serde_json::Value,
937    #[serde(default)]
938    pub unit_of_measure_labels: serde_json::Value,
939}
940
941// ---------------------------------------------------------------------------
942// §3.16  Document Texts
943// ---------------------------------------------------------------------------
944
945#[derive(Debug, Clone, Serialize, Deserialize, Default)]
946pub struct DocumentTextsConfig {
947    #[serde(default)]
948    pub purchase_order: DocumentTextGroup,
949    #[serde(default)]
950    pub goods_receipt: DocumentTextGroup,
951    #[serde(default)]
952    pub vendor_invoice: DocumentTextGroup,
953    #[serde(default)]
954    pub payment: DocumentTextGroup,
955    #[serde(default)]
956    pub sales_order: DocumentTextGroup,
957    #[serde(default)]
958    pub delivery: DocumentTextGroup,
959    #[serde(default)]
960    pub customer_invoice: DocumentTextGroup,
961    #[serde(default)]
962    pub customer_receipt: DocumentTextGroup,
963    /// Legacy field kept for backward compatibility with existing packs.
964    #[serde(default)]
965    pub invoice: DocumentTextGroup,
966    #[serde(default)]
967    pub journal_entry: DocumentTextGroup,
968}
969
970#[derive(Debug, Clone, Serialize, Deserialize, Default)]
971pub struct DocumentTextGroup {
972    /// Optional prefix for document IDs (e.g. "PO", "GR", "VI").
973    #[serde(default)]
974    pub reference_prefix: String,
975    #[serde(default)]
976    pub header_templates: Vec<String>,
977    #[serde(default)]
978    pub line_descriptions: Vec<String>,
979    #[serde(default)]
980    pub posting_texts: Vec<String>,
981}
982
983// ---------------------------------------------------------------------------
984// Emission factor (extension beyond spec — for ESG generator)
985// ---------------------------------------------------------------------------
986
987/// Country-level carbon intensity multiplier for spend-based Scope 3 emissions.
988#[derive(Debug, Clone, Serialize, Deserialize, Default)]
989pub struct EmissionFactorConfig {
990    #[serde(default = "default_emission_multiplier")]
991    pub country_multiplier: f64,
992}
993
994fn default_emission_multiplier() -> f64 {
995    1.0
996}
997
998#[cfg(test)]
999mod tests {
1000    use super::*;
1001
1002    #[test]
1003    fn test_default_country_pack() {
1004        let pack = CountryPack::default();
1005        assert!(pack.country_code.is_empty());
1006        assert!(pack.holidays.fixed.is_empty());
1007        assert!(pack.names.cultures.is_empty());
1008    }
1009
1010    #[test]
1011    fn test_deserialize_minimal_json() {
1012        let json =
1013            r#"{"schema_version": "1.0", "country_code": "US", "country_name": "United States"}"#;
1014        let pack: CountryPack = serde_json::from_str(json).expect("should parse");
1015        assert_eq!(pack.country_code, "US");
1016        assert_eq!(pack.schema_version, "1.0");
1017        assert!(pack.holidays.fixed.is_empty());
1018    }
1019
1020    #[test]
1021    fn test_deserialize_fixed_holiday() {
1022        let json = r#"{
1023            "name": "New Year's Day",
1024            "name_en": "New Year's Day",
1025            "month": 1,
1026            "day": 1,
1027            "activity_multiplier": 0.05,
1028            "observe_weekend_rule": true
1029        }"#;
1030        let h: FixedHoliday = serde_json::from_str(json).expect("should parse");
1031        assert_eq!(h.month, 1);
1032        assert_eq!(h.day, 1);
1033        assert!(h.observe_weekend_rule);
1034    }
1035
1036    #[test]
1037    fn test_deserialize_nth_weekday_holiday() {
1038        let json = r#"{
1039            "name": "MLK Day",
1040            "name_en": "Martin Luther King Jr. Day",
1041            "month": 1,
1042            "weekday": "monday",
1043            "occurrence": 3,
1044            "activity_multiplier": 0.1
1045        }"#;
1046        let h: NthWeekdayHoliday = serde_json::from_str(json).expect("should parse");
1047        assert_eq!(h.month, 1);
1048        assert_eq!(h.weekday, "monday");
1049        assert_eq!(h.occurrence, 3);
1050    }
1051}