Add numeric accounts as property to lib, redistribute floating point errors for each account in overhead allocation

This commit is contained in:
Piv
2023-03-09 22:28:05 +10:30
parent 5603ccfd25
commit 568a66c6cf
4 changed files with 35 additions and 5 deletions

View File

@@ -13,6 +13,8 @@ struct MoveMoney: View {
@State private var document: CsvDocument? @State private var document: CsvDocument?
@State private var lines: String? @State private var lines: String?
@State private var rules: String? @State private var rules: String?
@State private var costCentres: String?
@State private var accounts: String?
var body: some View { var body: some View {
VStack { VStack {
FileButtonSelector(label: "Select Rules File") { result in FileButtonSelector(label: "Select Rules File") { result in
@@ -21,6 +23,12 @@ struct MoveMoney: View {
FileButtonSelector(label: "Select Lines File") { result in FileButtonSelector(label: "Select Lines File") { result in
lines = result lines = result
} }
FileButtonSelector(label: "Select Cost Centres File") { result in
costCentres = result
}
FileButtonSelector(label: "Select Accounts File") { result in
accounts = result
}
Button { Button {
move_money() move_money()
} label: { } label: {
@@ -43,7 +51,7 @@ struct MoveMoney: View {
func move_money() { func move_money() {
DispatchQueue.global(qos: .userInitiated).async { DispatchQueue.global(qos: .userInitiated).async {
// Run move money // Run move money
let result = move_money_from_text(rules, lines, true) let result = move_money_from_text(rules, lines, accounts, costCentres, false)
DispatchQueue.main.async { DispatchQueue.main.async {
document = CsvDocument(data: String(cString: result!)) document = CsvDocument(data: String(cString: result!))

View File

@@ -55,7 +55,7 @@ struct OverheadAllocation: View {
func allocate_overheads() { func allocate_overheads() {
DispatchQueue.global(qos: .userInitiated).async { DispatchQueue.global(qos: .userInitiated).async {
// Run move money // Run move money
let result = allocate_overheads_from_text(lines, accounts, allocationStatistics, areas, costCentres, accountType); let result = allocate_overheads_from_text(lines, accounts, allocationStatistics, areas, costCentres, accountType, false);
DispatchQueue.main.async { DispatchQueue.main.async {
document = CsvDocument(data: String(cString: result!)) document = CsvDocument(data: String(cString: result!))

View File

@@ -80,6 +80,7 @@ pub extern "C" fn allocate_overheads_from_text(
areas: *const c_char, areas: *const c_char,
cost_centres: *const c_char, cost_centres: *const c_char,
account_type: *const c_char, account_type: *const c_char,
use_numeric_accounts: bool,
) -> *mut c_char { ) -> *mut c_char {
let lines = unsafe { let lines = unsafe {
assert!(!lines.is_null()); assert!(!lines.is_null());
@@ -113,7 +114,7 @@ pub extern "C" fn allocate_overheads_from_text(
csv::Reader::from_reader(areas.to_bytes()), csv::Reader::from_reader(areas.to_bytes()),
csv::Reader::from_reader(cost_centres.to_bytes()), csv::Reader::from_reader(cost_centres.to_bytes()),
&mut output_writer, &mut output_writer,
true, use_numeric_accounts,
false, false,
true, true,
account_type.to_str().unwrap().to_owned(), account_type.to_str().unwrap().to_owned(),

View File

@@ -549,7 +549,7 @@ fn do_solve_reciprocal<T: ReciprocalAllocationSolver>(
let calculated_overheads = solver.solve(&overhead_costs_vec); let calculated_overheads = solver.solve(&overhead_costs_vec);
let mut operating_slice_costs = vec![0.; operating_department_mappings.len()]; let mut operating_slice_costs = vec![0.; operating_department_mappings.len()];
for cost in total_costs.summed_department_costs { for cost in &total_costs.summed_department_costs {
if operating_department_mappings.contains_key(&cost.department) { if operating_department_mappings.contains_key(&cost.department) {
let elem = &mut operating_slice_costs let elem = &mut operating_slice_costs
[*operating_department_mappings.get(&cost.department).unwrap()]; [*operating_department_mappings.get(&cost.department).unwrap()];
@@ -579,9 +579,30 @@ fn do_solve_reciprocal<T: ReciprocalAllocationSolver>(
value: *calculated.get(*index).unwrap(), value: *calculated.get(*index).unwrap(),
}) })
.collect(); .collect();
// Redistribute floating point errors (only for ccs we actually allocated from/to)
// TODO: Still not sure if this is 100% correct, however it appears with this we match up
// with the line totals. I think this is because ppm just evenly redistributes floating point
// errors, whereas we keep the amounts proportional to the intial amounts
let initial_cost: f64 = total_costs
.summed_department_costs
.iter()
.filter(|cost| {
operating_department_mappings.contains_key(&cost.department)
|| overhead_department_mappings.contains_key(&cost.department)
})
.map(|cost| cost.value)
.sum();
let new_cost: f64 = converted_result.iter().map(|cost| cost.value).sum();
let diff = initial_cost - new_cost;
final_account_costs.push(AccountCost { final_account_costs.push(AccountCost {
account: total_costs.account, account: total_costs.account,
summed_department_costs: converted_result, summed_department_costs: converted_result
.into_iter()
.map(|cost| TotalDepartmentCost {
department: cost.department,
value: cost.value + cost.value / new_cost * diff,
})
.collect(),
}); });
} }
Ok(final_account_costs) Ok(final_account_costs)