1use super::{CompanyArchetype, Industry};
7use crate::models::{AccountMetadata, AccountNode, AccountSemantics, AccountType};
8use uuid::Uuid;
9
10#[derive(Debug, Clone)]
12pub struct ChartOfAccountsTemplate {
13 pub industry: Industry,
15 pub name: String,
17 pub accounts: Vec<AccountDefinition>,
19 pub expected_flows: Vec<ExpectedFlow>,
21}
22
23#[derive(Debug, Clone)]
25pub struct AccountDefinition {
26 pub code: String,
28 pub name: String,
30 pub account_type: AccountType,
32 pub class_id: u8,
34 pub subclass_id: u8,
36 pub parent_code: Option<String>,
38 pub semantics: u32,
40 pub typical_activity: f32,
42 pub description: String,
44}
45
46impl AccountDefinition {
47 pub fn new(
49 code: impl Into<String>,
50 name: impl Into<String>,
51 account_type: AccountType,
52 ) -> Self {
53 Self {
54 code: code.into(),
55 name: name.into(),
56 account_type,
57 class_id: 0,
58 subclass_id: 0,
59 parent_code: None,
60 semantics: 0,
61 typical_activity: 10.0,
62 description: String::new(),
63 }
64 }
65
66 pub fn with_class(mut self, class_id: u8, subclass_id: u8) -> Self {
68 self.class_id = class_id;
69 self.subclass_id = subclass_id;
70 self
71 }
72
73 pub fn with_parent(mut self, parent: impl Into<String>) -> Self {
75 self.parent_code = Some(parent.into());
76 self
77 }
78
79 pub fn with_semantics(mut self, semantics: u32) -> Self {
81 self.semantics = semantics;
82 self
83 }
84
85 pub fn with_activity(mut self, activity: f32) -> Self {
87 self.typical_activity = activity;
88 self
89 }
90
91 pub fn with_description(mut self, desc: impl Into<String>) -> Self {
93 self.description = desc.into();
94 self
95 }
96
97 pub fn to_account(&self, index: u16) -> (AccountNode, AccountMetadata) {
99 let mut node = AccountNode::new(Uuid::new_v4(), self.account_type, index);
100 node.class_id = self.class_id;
101 node.subclass_id = self.subclass_id;
102
103 let mut metadata = AccountMetadata::new(&self.code, &self.name);
104 metadata.description = self.description.clone();
105 metadata.semantics = AccountSemantics {
106 flags: self.semantics,
107 typical_frequency: self.typical_activity,
108 avg_amount_scale: 50.0, };
110
111 (node, metadata)
112 }
113}
114
115#[derive(Debug, Clone)]
117pub struct ExpectedFlow {
118 pub from_code: String,
120 pub to_code: String,
122 pub frequency: f64,
124 pub amount_range: (f64, f64),
126 pub description: String,
128}
129
130impl ExpectedFlow {
131 pub fn new(
133 from: impl Into<String>,
134 to: impl Into<String>,
135 frequency: f64,
136 amount_range: (f64, f64),
137 ) -> Self {
138 Self {
139 from_code: from.into(),
140 to_code: to.into(),
141 frequency,
142 amount_range,
143 description: String::new(),
144 }
145 }
146
147 pub fn with_description(mut self, desc: impl Into<String>) -> Self {
149 self.description = desc.into();
150 self
151 }
152}
153
154impl ChartOfAccountsTemplate {
155 pub fn gaap_minimal() -> Self {
157 Self {
158 industry: Industry::Retail,
159 name: "GAAP Minimal".to_string(),
160 accounts: vec![
161 AccountDefinition::new("1000", "Assets", AccountType::Asset)
163 .with_class(1, 0)
164 .with_description("Total assets"),
165 AccountDefinition::new("1100", "Cash", AccountType::Asset)
166 .with_class(1, 1)
167 .with_parent("1000")
168 .with_semantics(AccountSemantics::IS_CASH)
169 .with_activity(100.0)
170 .with_description("Cash and cash equivalents"),
171 AccountDefinition::new("1200", "Accounts Receivable", AccountType::Asset)
172 .with_class(1, 2)
173 .with_parent("1000")
174 .with_semantics(AccountSemantics::IS_RECEIVABLE)
175 .with_activity(50.0)
176 .with_description("Amounts owed by customers"),
177 AccountDefinition::new("1300", "Inventory", AccountType::Asset)
178 .with_class(1, 3)
179 .with_parent("1000")
180 .with_semantics(AccountSemantics::IS_INVENTORY)
181 .with_activity(30.0)
182 .with_description("Goods held for sale"),
183 AccountDefinition::new("1400", "Prepaid Expenses", AccountType::Asset)
184 .with_class(1, 4)
185 .with_parent("1000")
186 .with_activity(5.0)
187 .with_description("Expenses paid in advance"),
188 AccountDefinition::new("1500", "Fixed Assets", AccountType::Asset)
189 .with_class(1, 5)
190 .with_parent("1000")
191 .with_activity(2.0)
192 .with_description("Property, plant, and equipment"),
193 AccountDefinition::new("1510", "Accumulated Depreciation", AccountType::Contra)
194 .with_class(1, 5)
195 .with_parent("1500")
196 .with_semantics(AccountSemantics::IS_DEPRECIATION)
197 .with_activity(12.0)
198 .with_description("Accumulated depreciation on fixed assets"),
199 AccountDefinition::new("2000", "Liabilities", AccountType::Liability)
201 .with_class(2, 0)
202 .with_description("Total liabilities"),
203 AccountDefinition::new("2100", "Accounts Payable", AccountType::Liability)
204 .with_class(2, 1)
205 .with_parent("2000")
206 .with_semantics(AccountSemantics::IS_PAYABLE)
207 .with_activity(40.0)
208 .with_description("Amounts owed to suppliers"),
209 AccountDefinition::new("2200", "Accrued Expenses", AccountType::Liability)
210 .with_class(2, 2)
211 .with_parent("2000")
212 .with_activity(12.0)
213 .with_description("Expenses incurred but not yet paid"),
214 AccountDefinition::new("2300", "Unearned Revenue", AccountType::Liability)
215 .with_class(2, 3)
216 .with_parent("2000")
217 .with_activity(10.0)
218 .with_description("Revenue received but not yet earned"),
219 AccountDefinition::new("2400", "Notes Payable", AccountType::Liability)
220 .with_class(2, 4)
221 .with_parent("2000")
222 .with_activity(2.0)
223 .with_description("Short-term loans"),
224 AccountDefinition::new("3000", "Equity", AccountType::Equity)
226 .with_class(3, 0)
227 .with_description("Owner's equity"),
228 AccountDefinition::new("3100", "Common Stock", AccountType::Equity)
229 .with_class(3, 1)
230 .with_parent("3000")
231 .with_activity(1.0)
232 .with_description("Issued common shares"),
233 AccountDefinition::new("3200", "Retained Earnings", AccountType::Equity)
234 .with_class(3, 2)
235 .with_parent("3000")
236 .with_activity(1.0)
237 .with_description("Accumulated profits"),
238 AccountDefinition::new("4000", "Revenue", AccountType::Revenue)
240 .with_class(4, 0)
241 .with_semantics(AccountSemantics::IS_REVENUE)
242 .with_description("Total revenue"),
243 AccountDefinition::new("4100", "Sales Revenue", AccountType::Revenue)
244 .with_class(4, 1)
245 .with_parent("4000")
246 .with_semantics(AccountSemantics::IS_REVENUE)
247 .with_activity(100.0)
248 .with_description("Revenue from product sales"),
249 AccountDefinition::new("4200", "Service Revenue", AccountType::Revenue)
250 .with_class(4, 2)
251 .with_parent("4000")
252 .with_semantics(AccountSemantics::IS_REVENUE)
253 .with_activity(20.0)
254 .with_description("Revenue from services"),
255 AccountDefinition::new("5000", "Cost of Goods Sold", AccountType::Expense)
257 .with_class(5, 0)
258 .with_semantics(AccountSemantics::IS_COGS)
259 .with_activity(80.0)
260 .with_description("Direct cost of products sold"),
261 AccountDefinition::new("6000", "Operating Expenses", AccountType::Expense)
262 .with_class(6, 0)
263 .with_semantics(AccountSemantics::IS_EXPENSE)
264 .with_description("General operating expenses"),
265 AccountDefinition::new("6100", "Salaries Expense", AccountType::Expense)
266 .with_class(6, 1)
267 .with_parent("6000")
268 .with_semantics(AccountSemantics::IS_PAYROLL)
269 .with_activity(24.0)
270 .with_description("Employee salaries"),
271 AccountDefinition::new("6200", "Rent Expense", AccountType::Expense)
272 .with_class(6, 2)
273 .with_parent("6000")
274 .with_activity(12.0)
275 .with_description("Rent for facilities"),
276 AccountDefinition::new("6300", "Utilities Expense", AccountType::Expense)
277 .with_class(6, 3)
278 .with_parent("6000")
279 .with_activity(12.0)
280 .with_description("Electricity, water, gas"),
281 AccountDefinition::new("6400", "Depreciation Expense", AccountType::Expense)
282 .with_class(6, 4)
283 .with_parent("6000")
284 .with_activity(12.0)
285 .with_description("Depreciation of fixed assets"),
286 AccountDefinition::new("6500", "Marketing Expense", AccountType::Expense)
287 .with_class(6, 5)
288 .with_parent("6000")
289 .with_activity(20.0)
290 .with_description("Advertising and marketing"),
291 AccountDefinition::new("6900", "Other Expenses", AccountType::Expense)
292 .with_class(6, 9)
293 .with_parent("6000")
294 .with_activity(15.0)
295 .with_description("Miscellaneous expenses"),
296 AccountDefinition::new("9100", "Clearing Account", AccountType::Asset)
298 .with_class(9, 1)
299 .with_semantics(AccountSemantics::IS_SUSPENSE)
300 .with_activity(30.0)
301 .with_description("Temporary clearing account"),
302 ],
303 expected_flows: vec![
304 ExpectedFlow::new("4100", "1200", 0.30, (50.0, 5000.0))
306 .with_description("Credit sale: Revenue → A/R"),
307 ExpectedFlow::new("1200", "1100", 0.25, (50.0, 5000.0))
308 .with_description("Collection: A/R → Cash"),
309 ExpectedFlow::new("4100", "1100", 0.10, (20.0, 500.0))
310 .with_description("Cash sale: Revenue → Cash"),
311 ExpectedFlow::new("1300", "2100", 0.15, (100.0, 10000.0))
313 .with_description("Purchase: Inventory → A/P"),
314 ExpectedFlow::new("2100", "1100", 0.15, (100.0, 10000.0))
315 .with_description("Payment: A/P → Cash"),
316 ExpectedFlow::new("5000", "1300", 0.15, (50.0, 5000.0))
317 .with_description("Cost of sale: COGS → Inventory"),
318 ExpectedFlow::new("6100", "1100", 0.08, (5000.0, 50000.0))
320 .with_description("Payroll: Salaries → Cash"),
321 ExpectedFlow::new("6200", "1100", 0.04, (1000.0, 10000.0))
322 .with_description("Rent payment"),
323 ExpectedFlow::new("6300", "1100", 0.04, (200.0, 2000.0))
324 .with_description("Utilities payment"),
325 ExpectedFlow::new("6400", "1510", 0.04, (500.0, 5000.0))
326 .with_description("Depreciation: Expense → Accum Depr"),
327 ],
328 }
329 }
330
331 pub fn retail_standard() -> Self {
333 let mut template = Self::gaap_minimal();
334 template.industry = Industry::Retail;
335 template.name = "Retail Standard".to_string();
336
337 template.accounts.extend(vec![
339 AccountDefinition::new("1310", "Merchandise Inventory", AccountType::Asset)
341 .with_class(1, 3)
342 .with_parent("1300")
343 .with_semantics(AccountSemantics::IS_INVENTORY)
344 .with_activity(50.0),
345 AccountDefinition::new("1320", "Inventory in Transit", AccountType::Asset)
346 .with_class(1, 3)
347 .with_parent("1300")
348 .with_activity(10.0),
349 AccountDefinition::new("1110", "Cash Registers", AccountType::Asset)
351 .with_class(1, 1)
352 .with_parent("1100")
353 .with_semantics(AccountSemantics::IS_CASH)
354 .with_activity(200.0),
355 AccountDefinition::new("1120", "Undeposited Funds", AccountType::Asset)
356 .with_class(1, 1)
357 .with_parent("1100")
358 .with_semantics(AccountSemantics::IS_SUSPENSE | AccountSemantics::IS_CASH)
359 .with_activity(100.0),
360 AccountDefinition::new("1130", "Credit Card Receivable", AccountType::Asset)
362 .with_class(1, 1)
363 .with_parent("1100")
364 .with_activity(80.0),
365 AccountDefinition::new("4110", "Sales Returns", AccountType::Contra)
367 .with_class(4, 1)
368 .with_parent("4100")
369 .with_activity(20.0),
370 AccountDefinition::new("4120", "Sales Discounts", AccountType::Contra)
371 .with_class(4, 1)
372 .with_parent("4100")
373 .with_activity(15.0),
374 AccountDefinition::new("6510", "Store Supplies", AccountType::Expense)
376 .with_class(6, 5)
377 .with_parent("6500")
378 .with_activity(10.0),
379 AccountDefinition::new("6520", "Credit Card Fees", AccountType::Expense)
380 .with_class(6, 5)
381 .with_parent("6500")
382 .with_activity(30.0),
383 AccountDefinition::new("6530", "Shrinkage", AccountType::Expense)
384 .with_class(6, 5)
385 .with_parent("6500")
386 .with_activity(12.0),
387 ]);
388
389 template.expected_flows.extend(vec![
391 ExpectedFlow::new("1110", "1120", 0.20, (100.0, 5000.0))
392 .with_description("Register → Undeposited"),
393 ExpectedFlow::new("1120", "1100", 0.15, (1000.0, 20000.0))
394 .with_description("Bank deposit"),
395 ExpectedFlow::new("4110", "1200", 0.05, (20.0, 500.0)).with_description("Sales return"),
396 ExpectedFlow::new("6520", "1130", 0.08, (50.0, 500.0))
397 .with_description("CC processing fees"),
398 ]);
399
400 template
401 }
402
403 pub fn saas_standard() -> Self {
405 let mut template = Self::gaap_minimal();
406 template.industry = Industry::SaaS;
407 template.name = "SaaS Standard".to_string();
408
409 template.accounts.extend(vec![
411 AccountDefinition::new("2310", "Deferred Revenue - Current", AccountType::Liability)
413 .with_class(2, 3)
414 .with_parent("2300")
415 .with_activity(100.0),
416 AccountDefinition::new(
417 "2320",
418 "Deferred Revenue - Long-term",
419 AccountType::Liability,
420 )
421 .with_class(2, 3)
422 .with_parent("2300")
423 .with_activity(20.0),
424 AccountDefinition::new("4110", "Subscription Revenue", AccountType::Revenue)
426 .with_class(4, 1)
427 .with_parent("4100")
428 .with_semantics(AccountSemantics::IS_REVENUE)
429 .with_activity(200.0),
430 AccountDefinition::new("4120", "Professional Services", AccountType::Revenue)
431 .with_class(4, 2)
432 .with_parent("4200")
433 .with_activity(20.0),
434 AccountDefinition::new("5100", "Hosting Costs", AccountType::Expense)
436 .with_class(5, 1)
437 .with_parent("5000")
438 .with_activity(12.0),
439 AccountDefinition::new("5200", "Third-party Software", AccountType::Expense)
440 .with_class(5, 2)
441 .with_parent("5000")
442 .with_activity(24.0),
443 AccountDefinition::new("6510", "Customer Acquisition Cost", AccountType::Expense)
445 .with_class(6, 5)
446 .with_parent("6500")
447 .with_activity(50.0),
448 AccountDefinition::new("1410", "Deferred Commission", AccountType::Asset)
449 .with_class(1, 4)
450 .with_parent("1400")
451 .with_activity(30.0),
452 ]);
453
454 template.expected_flows = vec![
456 ExpectedFlow::new("1100", "2310", 0.25, (500.0, 50000.0))
457 .with_description("Annual subscription cash → Deferred revenue"),
458 ExpectedFlow::new("2310", "4110", 0.30, (50.0, 5000.0))
459 .with_description("Revenue recognition"),
460 ExpectedFlow::new("4110", "1200", 0.10, (100.0, 10000.0))
461 .with_description("Invoiced subscription"),
462 ExpectedFlow::new("1200", "1100", 0.15, (100.0, 10000.0))
463 .with_description("Collection"),
464 ExpectedFlow::new("5100", "2100", 0.08, (5000.0, 50000.0))
465 .with_description("Hosting invoice"),
466 ExpectedFlow::new("2100", "1100", 0.10, (1000.0, 50000.0))
467 .with_description("Vendor payment"),
468 ExpectedFlow::new("6510", "1100", 0.05, (1000.0, 20000.0))
469 .with_description("Marketing spend"),
470 ];
471
472 template
473 }
474
475 pub fn manufacturing_standard() -> Self {
483 let mut template = Self::gaap_minimal();
484 template.industry = Industry::Manufacturing;
485 template.name = "Manufacturing Standard".to_string();
486
487 template.accounts.extend(vec![
489 AccountDefinition::new("1310", "Raw Materials Inventory", AccountType::Asset)
491 .with_class(1, 3)
492 .with_parent("1300")
493 .with_semantics(AccountSemantics::IS_INVENTORY)
494 .with_activity(40.0)
495 .with_description("Materials awaiting production"),
496 AccountDefinition::new("1320", "Work in Progress", AccountType::Asset)
497 .with_class(1, 3)
498 .with_parent("1300")
499 .with_semantics(AccountSemantics::IS_INVENTORY)
500 .with_activity(60.0)
501 .with_description("Partially completed goods"),
502 AccountDefinition::new("1330", "Finished Goods Inventory", AccountType::Asset)
503 .with_class(1, 3)
504 .with_parent("1300")
505 .with_semantics(AccountSemantics::IS_INVENTORY)
506 .with_activity(50.0)
507 .with_description("Completed goods ready for sale"),
508 AccountDefinition::new("1340", "Factory Supplies", AccountType::Asset)
509 .with_class(1, 3)
510 .with_parent("1300")
511 .with_activity(15.0)
512 .with_description("Consumable manufacturing supplies"),
513 AccountDefinition::new("1520", "Manufacturing Equipment", AccountType::Asset)
515 .with_class(1, 5)
516 .with_parent("1500")
517 .with_activity(5.0)
518 .with_description("Production machinery"),
519 AccountDefinition::new(
520 "1525",
521 "Accum Depreciation - Mfg Equipment",
522 AccountType::Contra,
523 )
524 .with_class(1, 5)
525 .with_parent("1520")
526 .with_semantics(AccountSemantics::IS_DEPRECIATION)
527 .with_activity(12.0)
528 .with_description("Accumulated depreciation on manufacturing equipment"),
529 AccountDefinition::new("5100", "Direct Materials", AccountType::Expense)
531 .with_class(5, 1)
532 .with_parent("5000")
533 .with_semantics(AccountSemantics::IS_COGS)
534 .with_activity(100.0)
535 .with_description("Raw materials used in production"),
536 AccountDefinition::new("5200", "Direct Labor", AccountType::Expense)
537 .with_class(5, 2)
538 .with_parent("5000")
539 .with_semantics(AccountSemantics::IS_COGS | AccountSemantics::IS_PAYROLL)
540 .with_activity(60.0)
541 .with_description("Labor directly applied to production"),
542 AccountDefinition::new("5300", "Manufacturing Overhead", AccountType::Expense)
543 .with_class(5, 3)
544 .with_parent("5000")
545 .with_activity(30.0)
546 .with_description("Indirect manufacturing costs"),
547 AccountDefinition::new("5310", "Factory Utilities", AccountType::Expense)
548 .with_class(5, 3)
549 .with_parent("5300")
550 .with_activity(12.0)
551 .with_description("Factory electricity, water, gas"),
552 AccountDefinition::new("5320", "Indirect Labor", AccountType::Expense)
553 .with_class(5, 3)
554 .with_parent("5300")
555 .with_semantics(AccountSemantics::IS_PAYROLL)
556 .with_activity(24.0)
557 .with_description("Supervisory and maintenance labor"),
558 AccountDefinition::new("5330", "Equipment Maintenance", AccountType::Expense)
559 .with_class(5, 3)
560 .with_parent("5300")
561 .with_activity(12.0)
562 .with_description("Machine repairs and maintenance"),
563 AccountDefinition::new("5340", "Factory Depreciation", AccountType::Expense)
564 .with_class(5, 3)
565 .with_parent("5300")
566 .with_activity(12.0)
567 .with_description("Depreciation on manufacturing assets"),
568 AccountDefinition::new("9110", "Work Order Clearing", AccountType::Asset)
570 .with_class(9, 1)
571 .with_parent("9100")
572 .with_semantics(AccountSemantics::IS_SUSPENSE)
573 .with_activity(80.0)
574 .with_description("Production job cost accumulation"),
575 ]);
576
577 template.expected_flows = vec![
579 ExpectedFlow::new("1310", "2100", 0.20, (1000.0, 50000.0))
581 .with_description("Purchase raw materials on credit"),
582 ExpectedFlow::new("2100", "1100", 0.20, (1000.0, 50000.0))
583 .with_description("Pay supplier for materials"),
584 ExpectedFlow::new("5100", "1310", 0.25, (500.0, 20000.0))
586 .with_description("Issue materials to production"),
587 ExpectedFlow::new("1320", "5100", 0.15, (500.0, 20000.0))
588 .with_description("Accumulate direct materials in WIP"),
589 ExpectedFlow::new("1320", "5200", 0.15, (2000.0, 30000.0))
590 .with_description("Accumulate direct labor in WIP"),
591 ExpectedFlow::new("1320", "5300", 0.10, (1000.0, 15000.0))
592 .with_description("Allocate overhead to WIP"),
593 ExpectedFlow::new("1330", "1320", 0.20, (5000.0, 100000.0))
594 .with_description("Transfer completed goods from WIP"),
595 ExpectedFlow::new("5000", "1330", 0.25, (3000.0, 80000.0))
597 .with_description("Cost of goods sold from finished goods"),
598 ExpectedFlow::new("4100", "1200", 0.30, (5000.0, 150000.0))
599 .with_description("Revenue recognized on sale"),
600 ExpectedFlow::new("1200", "1100", 0.25, (5000.0, 150000.0))
601 .with_description("Customer payment received"),
602 ExpectedFlow::new("5200", "1100", 0.08, (10000.0, 100000.0))
604 .with_description("Direct labor payroll"),
605 ExpectedFlow::new("5320", "1100", 0.05, (5000.0, 40000.0))
606 .with_description("Indirect labor payroll"),
607 ];
608
609 template
610 }
611
612 pub fn professional_services_standard() -> Self {
620 let mut template = Self::gaap_minimal();
621 template.industry = Industry::ProfessionalServices;
622 template.name = "Professional Services".to_string();
623
624 template.accounts.extend(vec![
626 AccountDefinition::new("1210", "Unbilled Receivables", AccountType::Asset)
628 .with_class(1, 2)
629 .with_parent("1200")
630 .with_semantics(AccountSemantics::IS_RECEIVABLE)
631 .with_activity(100.0)
632 .with_description("Work completed but not yet invoiced"),
633 AccountDefinition::new("1220", "Work in Progress - Billable", AccountType::Asset)
634 .with_class(1, 2)
635 .with_parent("1200")
636 .with_activity(150.0)
637 .with_description("Time and expenses in progress"),
638 AccountDefinition::new("1230", "Reimbursable Expenses", AccountType::Asset)
639 .with_class(1, 2)
640 .with_parent("1200")
641 .with_activity(40.0)
642 .with_description("Client-reimbursable expenses pending"),
643 AccountDefinition::new("2310", "Client Retainers", AccountType::Liability)
645 .with_class(2, 3)
646 .with_parent("2300")
647 .with_activity(30.0)
648 .with_description("Advance payments from clients"),
649 AccountDefinition::new("2320", "Client Deposits", AccountType::Liability)
650 .with_class(2, 3)
651 .with_parent("2300")
652 .with_activity(20.0)
653 .with_description("Project deposits held"),
654 AccountDefinition::new("4110", "Professional Fees - Hourly", AccountType::Revenue)
656 .with_class(4, 1)
657 .with_parent("4100")
658 .with_semantics(AccountSemantics::IS_REVENUE)
659 .with_activity(200.0)
660 .with_description("Revenue from billable hours"),
661 AccountDefinition::new("4120", "Professional Fees - Fixed", AccountType::Revenue)
662 .with_class(4, 1)
663 .with_parent("4100")
664 .with_semantics(AccountSemantics::IS_REVENUE)
665 .with_activity(50.0)
666 .with_description("Revenue from fixed-fee projects"),
667 AccountDefinition::new("4130", "Retainer Fees", AccountType::Revenue)
668 .with_class(4, 1)
669 .with_parent("4100")
670 .with_semantics(AccountSemantics::IS_REVENUE)
671 .with_activity(40.0)
672 .with_description("Monthly retainer revenue"),
673 AccountDefinition::new("4210", "Reimbursed Expenses", AccountType::Revenue)
674 .with_class(4, 2)
675 .with_parent("4200")
676 .with_activity(30.0)
677 .with_description("Client-reimbursed expenses"),
678 AccountDefinition::new("5100", "Professional Labor Cost", AccountType::Expense)
680 .with_class(5, 1)
681 .with_parent("5000")
682 .with_semantics(AccountSemantics::IS_PAYROLL)
683 .with_activity(24.0)
684 .with_description("Cost of billable staff time"),
685 AccountDefinition::new("5200", "Subcontractor Fees", AccountType::Expense)
686 .with_class(5, 2)
687 .with_parent("5000")
688 .with_activity(20.0)
689 .with_description("Outside contractor costs"),
690 AccountDefinition::new("6110", "Professional Development", AccountType::Expense)
692 .with_class(6, 1)
693 .with_parent("6100")
694 .with_activity(12.0)
695 .with_description("Training and certifications"),
696 AccountDefinition::new("6510", "Business Development", AccountType::Expense)
697 .with_class(6, 5)
698 .with_parent("6500")
699 .with_activity(25.0)
700 .with_description("Client acquisition and networking"),
701 AccountDefinition::new(
702 "6520",
703 "Professional Liability Insurance",
704 AccountType::Expense,
705 )
706 .with_class(6, 5)
707 .with_parent("6500")
708 .with_activity(12.0)
709 .with_description("E&O insurance premiums"),
710 ]);
711
712 template.expected_flows = vec![
714 ExpectedFlow::new("1220", "5100", 0.30, (500.0, 20000.0))
716 .with_description("Record billable time as WIP"),
717 ExpectedFlow::new("1210", "1220", 0.25, (1000.0, 50000.0))
718 .with_description("Transfer completed WIP to unbilled"),
719 ExpectedFlow::new("1200", "1210", 0.25, (1000.0, 50000.0))
720 .with_description("Invoice unbilled work"),
721 ExpectedFlow::new("4110", "1200", 0.30, (1000.0, 50000.0))
722 .with_description("Recognize hourly fee revenue"),
723 ExpectedFlow::new("1200", "1100", 0.25, (1000.0, 50000.0))
724 .with_description("Client payment received"),
725 ExpectedFlow::new("1100", "2310", 0.10, (5000.0, 50000.0))
727 .with_description("Receive client retainer"),
728 ExpectedFlow::new("2310", "4130", 0.15, (1000.0, 10000.0))
729 .with_description("Apply retainer to revenue"),
730 ExpectedFlow::new("1230", "1100", 0.08, (100.0, 2000.0))
732 .with_description("Pay reimbursable expense"),
733 ExpectedFlow::new("4210", "1230", 0.08, (100.0, 2000.0))
734 .with_description("Bill reimbursable to client"),
735 ExpectedFlow::new("6100", "1100", 0.08, (10000.0, 100000.0))
737 .with_description("Staff payroll"),
738 ];
739
740 template
741 }
742
743 pub fn financial_services_standard() -> Self {
751 let mut template = Self::gaap_minimal();
752 template.industry = Industry::FinancialServices;
753 template.name = "Financial Services".to_string();
754
755 template.accounts.extend(vec![
757 AccountDefinition::new("1110", "Trading Securities", AccountType::Asset)
759 .with_class(1, 1)
760 .with_parent("1100")
761 .with_activity(500.0)
762 .with_description("Securities held for trading"),
763 AccountDefinition::new("1120", "Available-for-Sale Securities", AccountType::Asset)
764 .with_class(1, 1)
765 .with_parent("1100")
766 .with_activity(100.0)
767 .with_description("Securities available for sale"),
768 AccountDefinition::new("1130", "Held-to-Maturity Securities", AccountType::Asset)
769 .with_class(1, 1)
770 .with_parent("1100")
771 .with_activity(20.0)
772 .with_description("Securities held to maturity"),
773 AccountDefinition::new("1250", "Loans Receivable", AccountType::Asset)
775 .with_class(1, 2)
776 .with_parent("1200")
777 .with_semantics(AccountSemantics::IS_RECEIVABLE)
778 .with_activity(100.0)
779 .with_description("Outstanding loan portfolio"),
780 AccountDefinition::new("1255", "Allowance for Loan Losses", AccountType::Contra)
781 .with_class(1, 2)
782 .with_parent("1250")
783 .with_activity(24.0)
784 .with_description("Reserve for expected credit losses"),
785 AccountDefinition::new("1260", "Accrued Interest Receivable", AccountType::Asset)
786 .with_class(1, 2)
787 .with_parent("1200")
788 .with_activity(50.0)
789 .with_description("Interest earned but not yet received"),
790 AccountDefinition::new("1610", "Customer Custody Assets", AccountType::Asset)
792 .with_class(1, 6)
793 .with_parent("1600")
794 .with_activity(200.0)
795 .with_description("Assets held in custody for clients"),
796 AccountDefinition::new(
797 "2610",
798 "Customer Custody Liabilities",
799 AccountType::Liability,
800 )
801 .with_class(2, 6)
802 .with_parent("2600")
803 .with_activity(200.0)
804 .with_description("Obligation to return custody assets"),
805 AccountDefinition::new("2110", "Customer Deposits - Demand", AccountType::Liability)
807 .with_class(2, 1)
808 .with_parent("2100")
809 .with_activity(300.0)
810 .with_description("Checking/demand deposit accounts"),
811 AccountDefinition::new(
812 "2120",
813 "Customer Deposits - Savings",
814 AccountType::Liability,
815 )
816 .with_class(2, 1)
817 .with_parent("2100")
818 .with_activity(100.0)
819 .with_description("Savings deposit accounts"),
820 AccountDefinition::new("2130", "Customer Deposits - Time", AccountType::Liability)
821 .with_class(2, 1)
822 .with_parent("2100")
823 .with_activity(50.0)
824 .with_description("CDs and time deposits"),
825 AccountDefinition::new("3110", "Regulatory Capital Reserve", AccountType::Equity)
827 .with_class(3, 1)
828 .with_parent("3100")
829 .with_activity(12.0)
830 .with_description("Capital held for regulatory requirements"),
831 AccountDefinition::new("2510", "Accrued Interest Payable", AccountType::Liability)
832 .with_class(2, 5)
833 .with_parent("2500")
834 .with_activity(50.0)
835 .with_description("Interest owed but not yet paid"),
836 AccountDefinition::new("4110", "Interest Income - Loans", AccountType::Revenue)
838 .with_class(4, 1)
839 .with_parent("4100")
840 .with_semantics(AccountSemantics::IS_REVENUE)
841 .with_activity(100.0)
842 .with_description("Interest earned on loan portfolio"),
843 AccountDefinition::new("4120", "Interest Income - Securities", AccountType::Revenue)
844 .with_class(4, 1)
845 .with_parent("4100")
846 .with_semantics(AccountSemantics::IS_REVENUE)
847 .with_activity(80.0)
848 .with_description("Interest and dividends from investments"),
849 AccountDefinition::new("4130", "Trading Gains (Losses)", AccountType::Revenue)
850 .with_class(4, 1)
851 .with_parent("4100")
852 .with_activity(200.0)
853 .with_description("Net gains/losses from trading"),
854 AccountDefinition::new("4210", "Fee Income", AccountType::Revenue)
855 .with_class(4, 2)
856 .with_parent("4200")
857 .with_activity(150.0)
858 .with_description("Transaction and service fees"),
859 AccountDefinition::new("4220", "Custody Fees", AccountType::Revenue)
860 .with_class(4, 2)
861 .with_parent("4200")
862 .with_activity(50.0)
863 .with_description("Asset custody service fees"),
864 AccountDefinition::new("5100", "Interest Expense - Deposits", AccountType::Expense)
866 .with_class(5, 1)
867 .with_parent("5000")
868 .with_activity(100.0)
869 .with_description("Interest paid on customer deposits"),
870 AccountDefinition::new(
871 "5200",
872 "Interest Expense - Borrowings",
873 AccountType::Expense,
874 )
875 .with_class(5, 2)
876 .with_parent("5000")
877 .with_activity(50.0)
878 .with_description("Interest on wholesale borrowings"),
879 AccountDefinition::new("5300", "Provision for Loan Losses", AccountType::Expense)
880 .with_class(5, 3)
881 .with_parent("5000")
882 .with_activity(24.0)
883 .with_description("Additions to loan loss reserve"),
884 AccountDefinition::new("6110", "Compliance Costs", AccountType::Expense)
885 .with_class(6, 1)
886 .with_parent("6100")
887 .with_activity(24.0)
888 .with_description("Regulatory compliance expenses"),
889 AccountDefinition::new("6120", "Technology Infrastructure", AccountType::Expense)
890 .with_class(6, 1)
891 .with_parent("6100")
892 .with_activity(36.0)
893 .with_description("Trading systems and IT infrastructure"),
894 ]);
895
896 template.expected_flows = vec![
898 ExpectedFlow::new("1100", "2110", 0.20, (1000.0, 500000.0))
900 .with_description("Customer deposit received"),
901 ExpectedFlow::new("2110", "1100", 0.15, (500.0, 100000.0))
902 .with_description("Customer withdrawal"),
903 ExpectedFlow::new("1250", "1100", 0.10, (10000.0, 1000000.0))
905 .with_description("Loan disbursement"),
906 ExpectedFlow::new("1100", "1250", 0.12, (1000.0, 100000.0))
907 .with_description("Loan repayment principal"),
908 ExpectedFlow::new("1100", "4110", 0.15, (100.0, 50000.0))
909 .with_description("Loan interest payment"),
910 ExpectedFlow::new("1110", "1100", 0.25, (10000.0, 10000000.0))
912 .with_description("Security purchase"),
913 ExpectedFlow::new("1100", "1110", 0.25, (10000.0, 10000000.0))
914 .with_description("Security sale"),
915 ExpectedFlow::new("4130", "1110", 0.20, (100.0, 500000.0))
916 .with_description("Trading gain recognized"),
917 ExpectedFlow::new("5100", "2510", 0.10, (100.0, 100000.0))
919 .with_description("Accrue interest on deposits"),
920 ExpectedFlow::new("2510", "1100", 0.08, (100.0, 100000.0))
921 .with_description("Pay accrued interest"),
922 ExpectedFlow::new("4210", "1100", 0.15, (10.0, 10000.0))
924 .with_description("Transaction fees collected"),
925 ExpectedFlow::new("5300", "1255", 0.05, (1000.0, 100000.0))
927 .with_description("Provision for expected losses"),
928 ];
929
930 template
931 }
932
933 pub fn for_archetype(archetype: &CompanyArchetype) -> Self {
935 match archetype.industry() {
936 Industry::Retail => Self::retail_standard(),
937 Industry::SaaS => Self::saas_standard(),
938 Industry::Manufacturing => Self::manufacturing_standard(),
939 Industry::ProfessionalServices => Self::professional_services_standard(),
940 Industry::FinancialServices => Self::financial_services_standard(),
941 _ => Self::gaap_minimal(),
942 }
943 }
944
945 pub fn account_count(&self) -> usize {
947 self.accounts.len()
948 }
949
950 pub fn find_by_code(&self, code: &str) -> Option<&AccountDefinition> {
952 self.accounts.iter().find(|a| a.code == code)
953 }
954
955 pub fn accounts_by_type(&self, account_type: AccountType) -> Vec<&AccountDefinition> {
957 self.accounts
958 .iter()
959 .filter(|a| a.account_type == account_type)
960 .collect()
961 }
962}
963
964#[cfg(test)]
965mod tests {
966 use super::*;
967
968 #[test]
969 fn test_gaap_minimal() {
970 let template = ChartOfAccountsTemplate::gaap_minimal();
971 assert!(template.account_count() > 20);
972
973 assert!(!template.accounts_by_type(AccountType::Asset).is_empty());
975 assert!(!template.accounts_by_type(AccountType::Liability).is_empty());
976 assert!(!template.accounts_by_type(AccountType::Revenue).is_empty());
977 assert!(!template.accounts_by_type(AccountType::Expense).is_empty());
978 }
979
980 #[test]
981 fn test_retail_template() {
982 let template = ChartOfAccountsTemplate::retail_standard();
983 assert!(template.account_count() > 30);
984 assert_eq!(template.industry, Industry::Retail);
985
986 assert!(template.find_by_code("1110").is_some()); assert!(template.find_by_code("1120").is_some()); }
990
991 #[test]
992 fn test_saas_template() {
993 let template = ChartOfAccountsTemplate::saas_standard();
994 assert_eq!(template.industry, Industry::SaaS);
995
996 assert!(template.find_by_code("2310").is_some()); assert!(template.find_by_code("4110").is_some()); }
1000
1001 #[test]
1002 fn test_manufacturing_template() {
1003 let template = ChartOfAccountsTemplate::manufacturing_standard();
1004 assert_eq!(template.industry, Industry::Manufacturing);
1005 assert!(template.account_count() > 35);
1006
1007 assert!(template.find_by_code("1310").is_some()); assert!(template.find_by_code("1320").is_some()); assert!(template.find_by_code("1330").is_some()); assert!(template.find_by_code("5100").is_some()); assert!(template.find_by_code("5200").is_some()); assert!(template.find_by_code("5300").is_some()); assert!(template.find_by_code("1520").is_some()); assert!(!template.expected_flows.is_empty());
1022 }
1023
1024 #[test]
1025 fn test_professional_services_template() {
1026 let template = ChartOfAccountsTemplate::professional_services_standard();
1027 assert_eq!(template.industry, Industry::ProfessionalServices);
1028 assert!(template.account_count() > 35);
1029
1030 assert!(template.find_by_code("1210").is_some()); assert!(template.find_by_code("1220").is_some()); assert!(template.find_by_code("2310").is_some()); assert!(template.find_by_code("4110").is_some()); assert!(template.find_by_code("4130").is_some()); assert!(!template.expected_flows.is_empty());
1041 }
1042
1043 #[test]
1044 fn test_financial_services_template() {
1045 let template = ChartOfAccountsTemplate::financial_services_standard();
1046 assert_eq!(template.industry, Industry::FinancialServices);
1047 assert!(template.account_count() > 40);
1048
1049 assert!(template.find_by_code("1110").is_some()); assert!(template.find_by_code("1120").is_some()); assert!(template.find_by_code("1130").is_some()); assert!(template.find_by_code("1250").is_some()); assert!(template.find_by_code("1255").is_some()); assert!(template.find_by_code("2110").is_some()); assert!(template.find_by_code("2120").is_some()); assert!(template.find_by_code("4110").is_some()); assert!(template.find_by_code("5100").is_some()); assert!(template.find_by_code("1610").is_some()); assert!(template.find_by_code("4220").is_some()); assert!(!template.expected_flows.is_empty());
1072 }
1073}