diff --git a/lib/biz/bizmodel/act.v b/lib/biz/bizmodel/act.v new file mode 100644 index 00000000..a11f989c --- /dev/null +++ b/lib/biz/bizmodel/act.v @@ -0,0 +1,154 @@ +module bizmodel + +import freeflowuniverse.herolib.core.texttools +import freeflowuniverse.herolib.core.playbook { PlayBook, Action } +import freeflowuniverse.herolib.ui.console +// import freeflowuniverse.herolib.core.texttools +// import freeflowuniverse.herolib.ui.console +import freeflowuniverse.herolib.biz.spreadsheet + +pub fn (mut m BizModel) act(action Action) !Action { + return match texttools.snake_case(action.name) { + 'funding_define' { + m.funding_define_action(action)! + } + 'revenue_define' { + m.funding_define_action(action)! + } + 'costcenter_define' { + m.costcenter_define_action(action)! + } + 'cost_define' { + m.cost_define_action(action)! + } + 'department_define' { + m.department_define_action(action)! + } + 'employee_define' { + m.employee_define_action(action)! + } + 'new_report' { + m.new_report_action(action)! + } + 'sheet_wiki' { + m.export_sheet_action(action)! + } + 'graph_bar_row' { + m.export_graph_bar_action(action)! + } + 'graph_pie_row' { + m.export_graph_pie_action(action)! + } + 'graph_line_row' { + m.export_graph_line_action(action)! + } + 'row_overview' { + m.export_overview_action(action)! + } + else { + return error('Unknown operation: ${action.name}') + } + } +} + +fn (mut m BizModel) export_sheet_action(action Action) !Action { + return m.export_action(m.sheet.wiki(row_args_from_params(action.params)!)!, action) +} + +fn (mut m BizModel) export_graph_title_action(action Action) !Action { + return m.export_action(m.sheet.wiki_title_chart(row_args_from_params(action.params)!), action) +} + +fn (mut m BizModel) export_graph_line_action(action Action) !Action { + return m.export_action(m.sheet.wiki_line_chart(row_args_from_params(action.params)!)!, action) +} + +fn (mut m BizModel) export_graph_bar_action(action Action) !Action { + return m.export_action(m.sheet.wiki_bar_chart(row_args_from_params(action.params)!)!, action) +} + +pub fn (mut m BizModel) export_graph_pie_action(action Action) !Action { + return m.export_action(m.sheet.wiki_pie_chart(row_args_from_params(action.params)!)!, action) +} + +pub fn (mut m BizModel) export_overview_action(action Action) !Action { + return m.export_action(m.sheet.wiki_row_overview(row_args_from_params(action.params)!)!, action) +} + +fn (mut m BizModel) export_action(action Action) !Action { + m.export(paramsparser.decode[Export](action.params))! + return action +} + +// fetches args for getting row from params +pub fn row_args_from_params(p Params) !RowGetArgs { + rowname := p.get_default('rowname', '')! + namefilter := p.get_list_default('namefilter', [])! + includefilter := p.get_list_default('includefilter', [])! + excludefilter := p.get_list_default('excludefilter', [])! + size := p.get_default('size', '')! + title_sub := p.get_default('title_sub', '')! + title := p.get_default('title', '')! + unit := p.get_default('unit', 'normal')! + unit_e := match unit { + 'thousand' { UnitType.thousand } + 'million' { UnitType.million } + 'billion' { UnitType.billion } + else { UnitType.normal } + } + period_type := p.get_default('period_type', 'year')! + if period_type !in ['year', 'month', 'quarter'] { + return error('period type needs to be in year,month,quarter') + } + period_type_e := match period_type { + 'year' { PeriodType.year } + 'month' { PeriodType.month } + 'quarter' { PeriodType.quarter } + else { PeriodType.error } + } + if period_type_e == .error { + return error('period type needs to be in year,month,quarter') + } + + rowname_show := p.get_default_true('rowname_show') + descr_show := p.get_default_true('descr_show') + + return RowGetArgs{ + rowname: rowname + namefilter: namefilter + includefilter: includefilter + excludefilter: excludefilter + period_type: period_type_e + unit: unit_e + title_sub: title_sub + title: title + size: size + rowname_show: rowname_show + descr_show: descr_show + } +} + +// creates the name for a file being exported given the params of the export action +fn (m BizModel) export_action(content string, action Action) !Action { + + // determine name of file being exported + name := if action.params.exists('name') { action.params.get('name')! } else { + if action.params.exists('title') { action.params.get('title')! } else { + // if no name or title, name is ex: revenue_total_graph_bar_row + rowname := action.params.get_default('rowname', '')! + '${rowname}_${action.name}' + } + } + + // by default exports to working dir of bizmodel + destination := action.params.get_default('destination', m.workdir)! + + mut path := pathlib.get_file( + path: os.join_path(destination, name) + increment: true + empty: action.params.get_default_false('overwrite') + )! + + path.write(content)! + return action +} \ No newline at end of file diff --git a/lib/biz/bizmodel/factory.v b/lib/biz/bizmodel/factory.v index c3118da3..6a515a9c 100644 --- a/lib/biz/bizmodel/factory.v +++ b/lib/biz/bizmodel/factory.v @@ -11,8 +11,8 @@ pub fn get(name string) !&BizModel { if name in bizmodels { return bizmodels[name] or { panic('bug') } } + return error("cann't find biz model:'${name}' in global bizmodels ${bizmodels.keys()}") } - return error("cann't find biz model:'${name}' in global bizmodels") } // get bizmodel from global diff --git a/lib/biz/bizmodel/model.v b/lib/biz/bizmodel/model.v index ca311d02..fa9bf6e7 100644 --- a/lib/biz/bizmodel/model.v +++ b/lib/biz/bizmodel/model.v @@ -1,10 +1,12 @@ module bizmodel +import os import freeflowuniverse.herolib.biz.spreadsheet pub struct BizModel { pub mut: name string + workdir string = '${os.home_dir()}/hero/var/bizmodel' sheet &spreadsheet.Sheet employees map[string]&Employee departments map[string]&Department diff --git a/lib/biz/bizmodel/play.v b/lib/biz/bizmodel/play.v index 21756966..ba8b9cdc 100644 --- a/lib/biz/bizmodel/play.v +++ b/lib/biz/bizmodel/play.v @@ -1,89 +1,50 @@ module bizmodel -import freeflowuniverse.herolib.core.playbook { PlayBook } +import freeflowuniverse.herolib.core.texttools +import freeflowuniverse.herolib.core.playbook { PlayBook, Action } import freeflowuniverse.herolib.ui.console // import freeflowuniverse.herolib.core.texttools // import freeflowuniverse.herolib.ui.console import freeflowuniverse.herolib.biz.spreadsheet -pub fn play(mut plbook PlayBook) ! { - // first make sure we find a run action to know the name - mut actions4 := plbook.actions_find(actor: 'bizmodel')! - - if actions4.len == 0 { - return - } - - knownactions := ['revenue_define', 'employee_define', 'department_define', 'funding_define', - 'costcenter_define', 'cost_define'] - - for action in actions4 { - // biz name needs to be specified in the the bizmodel hero actions - bizname := action.params.get('bizname') or { - return error("Can't find param: 'bizname' for ${action.actor}.${action.name} macro, is a requirement argument.") - } - mut sim := getset(bizname)! - - if action.name !in knownactions { - return error("Can't find macro with name: ${action.name} for macro's for bizmodel.") - } - - console.print_debug(action.name) - match action.name { - 'revenue_define' { - sim.revenue_action(action)! - } - 'funding_define' { - sim.funding_define_action(action)! - } - 'costcenter_define' { - sim.costcenter_define_action(action)! - } - else {} - } - } - - console.print_debug('TOTALS for bizmodel play') - // now we have processed the macro's, we can calculate the totals - rlock bizmodels { - for _, mut sim in bizmodels { - // sim.hr_total()! - sim.cost_total()! - sim.revenue_total()! - sim.funding_total()! - } - } - - for action in actions4 { - console.print_debug(action.name) - // biz name needs to be specified in the the bizmodel hero actions - bizname := action.params.get('bizname') or { - return error("Can't find param: 'bizname' for bizmodel macro, is a requirement argument.") - } - - mut sim := get(bizname)! - - if action.name !in knownactions { - return error("Can't find macro with name: ${action.name} for macro's for bizmodel.") - } - - match action.name { - 'cost_define' { - sim.cost_define_action(action)! - } - 'department_define' { - sim.department_define_action(action)! - } - 'employee_define' { - sim.employee_define_action(action)! - } - else {} - } - } - - // mut sim:=get("test")! - // //println(sim.sheet.rows.keys()) - // //println(spreadsheet.sheets_keys()) - // println(spreadsheet.sheet_get('bizmodel_test')!) - // if true{panic("sss")} +const action_priorities = { + 0: ['revenue_define', 'costcenter_define', 'funding_define'] + 1: ['cost_define', 'department_define', 'employee_define'] + 2: ['sheet_wiki', 'graph_bar_row', 'graph_pie_row', 'graph_line_row', 'row_overview'] } + +pub fn play(mut plbook PlayBook) ! { + // group actions by which bizmodel they belong to + actions_by_biz := arrays.group_by[string, Action]( + plbook.actions_find(actor: 'bizmodel')!, + fn (a Action) string { + return action.params.get('bizname') or {'default'} + } + ) + + // play actions for each biz in playbook + for biz, actions in actions_by_biz { + mut model := getset(bizname)! + model.play(mut plbook)! + } +} + +pub fn (mut m BizModel) play(mut plbook PlayBook) ! { + mut actions := plbook.actions_find(actor: 'bizmodel')! + + for action in actions.filter(it.name in action_priorities[0]) { + m.act(*action)! + } + + m.cost_total()! + m.revenue_total()! + m.funding_total()! + + for action in actions.filter(it.name in action_priorities[1]) { + m.act(*action)! + } + + for action in actions.filter(it.name in action_priorities[2]) { + m.act(*action)! + } +} \ No newline at end of file diff --git a/lib/biz/bizmodel/play_cost.v b/lib/biz/bizmodel/play_cost.v index ee015d65..374bee02 100644 --- a/lib/biz/bizmodel/play_cost.v +++ b/lib/biz/bizmodel/play_cost.v @@ -3,7 +3,7 @@ module bizmodel import freeflowuniverse.herolib.core.playbook { Action } import freeflowuniverse.herolib.core.texttools -fn (mut m BizModel) cost_define_action(action Action) ! { +fn (mut m BizModel) cost_define_action(action Action) !Action { mut name := action.params.get_default('name', '')! mut descr := action.params.get_default('descr', '')! if descr.len == 0 { @@ -73,6 +73,7 @@ fn (mut m BizModel) cost_define_action(action Action) ! { )! m.sheet.row_delete('tmp3') } + return action } fn (mut sim BizModel) cost_total() ! { diff --git a/lib/biz/bizmodel/play_costcenter.v b/lib/biz/bizmodel/play_costcenter.v index a3cb25c7..a26c2343 100644 --- a/lib/biz/bizmodel/play_costcenter.v +++ b/lib/biz/bizmodel/play_costcenter.v @@ -3,7 +3,7 @@ module bizmodel import freeflowuniverse.herolib.core.playbook { Action } import freeflowuniverse.herolib.core.texttools -fn (mut m BizModel) costcenter_define_action(action Action) ! { +fn (mut m BizModel) costcenter_define_action(action Action) !Action { mut name := action.params.get_default('name', '')! mut descr := action.params.get_default('descr', '')! if descr.len == 0 { @@ -20,4 +20,5 @@ fn (mut m BizModel) costcenter_define_action(action Action) ! { department: department } m.costcenters[name] = &cc + return action } diff --git a/lib/biz/bizmodel/play_funding.v b/lib/biz/bizmodel/play_funding.v index 71644dc9..c8af269f 100644 --- a/lib/biz/bizmodel/play_funding.v +++ b/lib/biz/bizmodel/play_funding.v @@ -9,7 +9,7 @@ import freeflowuniverse.herolib.core.texttools // - descr: description of the funding . // - investment is month:amount,month:amount, ... . // - type: loan or capital . -fn (mut m BizModel) funding_define_action(action Action) ! { +fn (mut m BizModel) funding_define_action(action Action) !Action { mut name := action.params.get_default('name', '')! mut descr := action.params.get_default('descr', '')! if descr.len == 0 { @@ -29,6 +29,7 @@ fn (mut m BizModel) funding_define_action(action Action) ! { descr: descr extrapolate: false )! + return action } fn (mut sim BizModel) funding_total() ! { diff --git a/lib/biz/bizmodel/play_hr.v b/lib/biz/bizmodel/play_hr.v index 97abbf92..9bf0ea46 100644 --- a/lib/biz/bizmodel/play_hr.v +++ b/lib/biz/bizmodel/play_hr.v @@ -15,7 +15,7 @@ import freeflowuniverse.herolib.core.texttools // department:'engineering' // cost_percent_revenue e.g. 4%, will make sure the cost will be at least 4% of revenue -fn (mut m BizModel) employee_define_action(action Action) ! { +fn (mut m BizModel) employee_define_action(action Action) !Action { mut name := action.params.get_default('name', '')! mut descr := action.params.get_default('descr', '')! if descr.len == 0 { @@ -107,10 +107,7 @@ fn (mut m BizModel) employee_define_action(action Action) ! { fulltime_perc: action.params.get_percentage_default('fulltime', '100%')! } - // println(employee) - // todo: use existing id gen - if name != '' { // sid = smartid.sid_new('')! // // TODO: this isn't necessary if sid_new works correctly @@ -120,9 +117,10 @@ fn (mut m BizModel) employee_define_action(action Action) ! { // } m.employees[name] = &employee } + return action } -fn (mut m BizModel) department_define_action(action Action) ! { +fn (mut m BizModel) department_define_action(action Action) !Action { mut name := action.params.get_default('name', '')! mut descr := action.params.get_default('descr', '')! if descr.len == 0 { @@ -141,6 +139,8 @@ fn (mut m BizModel) department_define_action(action Action) ! { if name != '' { m.departments[name] = &department } + + return action } // fn (mut sim BizModel) hr_total() ! { diff --git a/lib/biz/bizmodel/play_product_revenue.v b/lib/biz/bizmodel/play_product_revenue.v index 2a3015fb..4b7fe804 100644 --- a/lib/biz/bizmodel/play_product_revenue.v +++ b/lib/biz/bizmodel/play_product_revenue.v @@ -21,7 +21,7 @@ import freeflowuniverse.herolib.core.texttools // - nr_sold: how many do we sell per month (is in growth format e.g. 10:100,20:200) // - nr_months_recurring: how many months is recurring, if 0 then no recurring // -fn (mut m BizModel) revenue_action(action Action) ! { +fn (mut m BizModel) revenue_action(action Action) !Action { mut name := action.params.get_default('name', '')! mut descr := action.params.get_default('descr', '')! if descr.len == 0 { @@ -312,6 +312,7 @@ fn (mut m BizModel) revenue_action(action Action) ! { // panic("sdsd") // } + return action } // revenue_total calculates and aggregates the total revenue and cost of goods sold (COGS) for the business model