Implement overhead allocation for different account types, add it to binaries

This commit is contained in:
Piv
2023-02-10 21:46:19 +10:30
parent d1eb0b6e35
commit 51ece6317f
10 changed files with 442 additions and 172 deletions

View File

@@ -8,6 +8,6 @@
#ifndef coster_bridge_h
#define coster_bridge_h
#import "libcoster_rs.h"
#import "coster.h"
#endif /* coster_bridge_h */

View File

@@ -1,8 +0,0 @@
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
char *move_money_from_text(const char *rules, const char *lines, bool use_numeric_accounts);
void move_money_from_text_free(char *s);

View File

@@ -7,6 +7,9 @@
objects = {
/* Begin PBXBuildFile section */
5A1986F72996436500FA0471 /* OverheadAllocation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A1986F62996436500FA0471 /* OverheadAllocation.swift */; };
5A1986F92996436D00FA0471 /* MoveMoney.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A1986F82996436D00FA0471 /* MoveMoney.swift */; };
5A1986FB2996502C00FA0471 /* FileButtonSelector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A1986FA2996502C00FA0471 /* FileButtonSelector.swift */; };
5A450751298CE6D500E3D402 /* CsvDocument.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A450750298CE6D500E3D402 /* CsvDocument.swift */; };
5A45075B298D01EF00E3D402 /* libcoster_rs.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5A45075A298D01EF00E3D402 /* libcoster_rs.a */; };
5ADD9F2D298A713300F998F5 /* FastCosterApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5ADD9F2C298A713300F998F5 /* FastCosterApp.swift */; };
@@ -36,12 +39,15 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
5A1986F62996436500FA0471 /* OverheadAllocation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverheadAllocation.swift; sourceTree = "<group>"; };
5A1986F82996436D00FA0471 /* MoveMoney.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoveMoney.swift; sourceTree = "<group>"; };
5A1986FA2996502C00FA0471 /* FileButtonSelector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileButtonSelector.swift; sourceTree = "<group>"; };
5A1986FD29965BED00FA0471 /* coster.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = coster.h; path = ../../coster.h; sourceTree = "<group>"; };
5A450750298CE6D500E3D402 /* CsvDocument.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CsvDocument.swift; sourceTree = "<group>"; };
5A450754298CFFAB00E3D402 /* coster-bridge.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "coster-bridge.h"; sourceTree = "<group>"; };
5A450755298CFFE400E3D402 /* create-lib.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "create-lib.sh"; sourceTree = "<group>"; };
5A450756298D00AE00E3D402 /* remove-lib.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "remove-lib.sh"; sourceTree = "<group>"; };
5A45075A298D01EF00E3D402 /* libcoster_rs.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libcoster_rs.a; path = "../costerrs/target/aarch64-apple-ios/release/libcoster_rs.a"; sourceTree = "<group>"; };
5ACE47E6298D087B00834311 /* libcoster_rs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = libcoster_rs.h; sourceTree = "<group>"; };
5ADD9F29298A713300F998F5 /* FastCoster.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FastCoster.app; sourceTree = BUILT_PRODUCTS_DIR; };
5ADD9F2C298A713300F998F5 /* FastCosterApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FastCosterApp.swift; sourceTree = "<group>"; };
5ADD9F2E298A713300F998F5 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
@@ -85,7 +91,7 @@
isa = PBXGroup;
children = (
5A450754298CFFAB00E3D402 /* coster-bridge.h */,
5ACE47E6298D087B00834311 /* libcoster_rs.h */,
5A1986FD29965BED00FA0471 /* coster.h */,
5A450755298CFFE400E3D402 /* create-lib.sh */,
5A450756298D00AE00E3D402 /* remove-lib.sh */,
);
@@ -131,6 +137,9 @@
5ADD9F32298A713400F998F5 /* FastCoster.entitlements */,
5ADD9F33298A713400F998F5 /* Preview Content */,
5A450750298CE6D500E3D402 /* CsvDocument.swift */,
5A1986F62996436500FA0471 /* OverheadAllocation.swift */,
5A1986F82996436D00FA0471 /* MoveMoney.swift */,
5A1986FA2996502C00FA0471 /* FileButtonSelector.swift */,
);
path = FastCoster;
sourceTree = "<group>";
@@ -310,7 +319,7 @@
5A450758298D014E00E3D402 /* Remove Rust Lib */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
buildActionMask = 8;
files = (
);
inputFileListPaths = (
@@ -322,7 +331,7 @@
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
runOnlyForDeploymentPostprocessing = 1;
shellPath = /bin/sh;
shellScript = "source ${PROJECT_DIR}/CosterRs/remove-lib.sh\n";
showEnvVarsInLog = 0;
@@ -334,9 +343,12 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
5A1986FB2996502C00FA0471 /* FileButtonSelector.swift in Sources */,
5ADD9F2F298A713300F998F5 /* ContentView.swift in Sources */,
5A1986F92996436D00FA0471 /* MoveMoney.swift in Sources */,
5ADD9F2D298A713300F998F5 /* FastCosterApp.swift in Sources */,
5A450751298CE6D500E3D402 /* CsvDocument.swift in Sources */,
5A1986F72996436500FA0471 /* OverheadAllocation.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@@ -7,90 +7,37 @@
import SwiftUI
enum ProcessType: String, Hashable {
case MoveMoney = "Move Money"
case OverheadAllocation = "Overhead Allocation"
static let values = [MoveMoney, OverheadAllocation]
}
struct ContentView: View {
@State private var showRulesPicker = false
@State private var showLinesPicker = false
@State private var showExportPicker = false
@State private var document: CsvDocument?
@State private var lines: String?
@State private var rules: String?
@State var selectedProcess: ProcessType?
var body: some View {
VStack {
Text ("Fast Coster").font(.largeTitle)
Spacer()
Button {
showRulesPicker.toggle()
} label: {
Text("Select Rules File")
}.fileImporter(isPresented: $showRulesPicker, allowedContentTypes: [.commaSeparatedText]) { result in
NavigationSplitView {
List(ProcessType.values, id: \.self, selection: $selectedProcess) { process in
NavigationLink(process.rawValue, value: process)
}
} detail: {
if let process = selectedProcess {
switch process {
case .MoveMoney:
MoveMoney()
switch result {
case .success(let fileUrl):
rules = readIntoString(selectedFile: fileUrl)
case .failure(let error):
print(error)
case .OverheadAllocation:
OverheadAllocation()
}
}.padding()
Button {
showLinesPicker.toggle()
} label: {
Text("Select Lines File")
}.fileImporter(isPresented: $showLinesPicker, allowedContentTypes: [.commaSeparatedText]) { result in
switch result {
case .success(let fileUrl):
lines = readIntoString(selectedFile: fileUrl)
case .failure(let error):
print(error)
}
}.padding()
Button {
move_money()
} label: {
Text("Move money")
}.padding()
Spacer()
}
.padding()
.fileExporter(isPresented: $showExportPicker, document: document, contentType: .commaSeparatedText) { result in
if case .success = result {
}else {
}
}
}
func move_money() {
DispatchQueue.global(qos: .userInitiated).async {
// Run move money
let result = move_money_from_text(rules, lines, true)
DispatchQueue.main.async {
document = CsvDocument(data: String(cString: result!))
move_money_from_text_free(result)
showExportPicker = true;
} else {
MoveMoney()
}
}
}
func readIntoString(selectedFile: URL) -> String {
// https://stackoverflow.com/questions/64118577/getting-the-file-xxx-couldnt-be-opened-because-you-dont-have-permission-to-v
do {
if selectedFile.startAccessingSecurityScopedResource() {
let fileContent = try String(contentsOf: selectedFile)
defer { selectedFile.stopAccessingSecurityScopedResource() }
return fileContent
}
}catch let error {
// TODO: Do something about this
print(error)
}
return ""
}
}
struct ContentView_Previews: PreviewProvider {

View File

@@ -0,0 +1,53 @@
//
// FileButtonSelector.swift
// FastCoster
//
// Created by Michael Pivato on 10/2/2023.
//
import SwiftUI
struct FileButtonSelector: View {
@State private var showPicker = false
var label: String
var onSelected: (String) -> ()
var body: some View {
Button {
showPicker.toggle()
} label: {
Text(label)
}.fileImporter(isPresented: $showPicker, allowedContentTypes: [.commaSeparatedText]) { result in
switch result {
case .success(let fileUrl):
onSelected(readIntoString(selectedFile: fileUrl))
case .failure(let error):
print(error)
}
}.padding()
}
func readIntoString(selectedFile: URL) -> String {
// https://stackoverflow.com/questions/64118577/getting-the-file-xxx-couldnt-be-opened-because-you-dont-have-permission-to-v
do {
if selectedFile.startAccessingSecurityScopedResource() {
let fileContent = try String(contentsOf: selectedFile)
defer { selectedFile.stopAccessingSecurityScopedResource() }
return fileContent
}
}catch let error {
// TODO: Do something about this
print(error)
}
return ""
}
}
struct FileButtonSelector_Previews: PreviewProvider {
static var previews: some View {
FileButtonSelector(label: "Select File"){ response in
}
}
}

View File

@@ -0,0 +1,61 @@
//
// MoveMoney.swift
// FastCoster
//
// Created by Michael Pivato on 10/2/2023.
//
import SwiftUI
struct MoveMoney: View {
@State private var showExportPicker = false
@State private var document: CsvDocument?
@State private var lines: String?
@State private var rules: String?
var body: some View {
VStack {
FileButtonSelector(label: "Select Rules File") { result in
rules = result
}
FileButtonSelector(label: "Select Lines File") { result in
lines = result
}
Button {
move_money()
} label: {
Text("Move money")
}.padding()
.fileExporter(isPresented: $showExportPicker, document: document, contentType: .commaSeparatedText) { result in
if case .success = result {
}else {
}
}
}
.padding()
}
func move_money() {
DispatchQueue.global(qos: .userInitiated).async {
// Run move money
let result = move_money_from_text(rules, lines, true)
DispatchQueue.main.async {
document = CsvDocument(data: String(cString: result!))
move_money_from_text_free(result)
showExportPicker = true;
}
}
}
}
struct MoveMoney_Previews: PreviewProvider {
static var previews: some View {
MoveMoney()
}
}

View File

@@ -0,0 +1,73 @@
//
// OverheadAllocation.swift
// FastCoster
//
// Created by Michael Pivato on 10/2/2023.
//
import SwiftUI
struct OverheadAllocation: View {
@State private var lines: String?
@State private var accounts: String?
@State private var areas: String?
@State private var allocationStatistics: String?
@State private var costCentres: String?
@State private var showExportPicker = false
@State private var document: CsvDocument?
@State private var accountType = "E"
var body: some View {
VStack {
FileButtonSelector(label: "Select Lines File") {result in
lines = result
}
FileButtonSelector(label: "Select Accounts File") {result in
accounts = result
}
FileButtonSelector(label: "Select Areas File") {result in
areas = result
}
FileButtonSelector(label: "Select Allocation Statistics File") {result in
allocationStatistics = result
}
FileButtonSelector(label: "Select Cost Centres File") {result in
costCentres = result
}
TextField("Account Type", text: $accountType)
Button {
allocate_overheads()
} label: {
Text("Allocate Overheads")
}.padding()
.fileExporter(isPresented: $showExportPicker, document: document, contentType: .commaSeparatedText) { result in
if case .success = result {
}else {
}
}
}
}
func allocate_overheads() {
DispatchQueue.global(qos: .userInitiated).async {
// Run move money
let result = allocate_overheads_from_text(lines, accounts, allocationStatistics, areas, costCentres, accountType);
DispatchQueue.main.async {
document = CsvDocument(data: String(cString: result!))
allocate_overheads_from_text_free(result)
showExportPicker = true;
}
}
}
}
struct OverheadAllocation_Previews: PreviewProvider {
static var previews: some View {
OverheadAllocation()
}
}