diff --git a/frontend/Calculator.elm b/frontend/Calculator.elm new file mode 100644 index 0000000..71043ee --- /dev/null +++ b/frontend/Calculator.elm @@ -0,0 +1,103 @@ +module Calculator exposing (..) + +import Html exposing (..) +import Html.Attributes exposing (..) +import Html.Events exposing (..) + +import NumberInput +import Select + +type Tax = Net | Gross + +ctShow ct = case ct of + Gross -> "Brutto" + Net -> "Netto" + +type alias Model = + { tax : Select.Model Tax + , bundlePrice : NumberInput.Model Float + , bundleSize : NumberInput.Model Int + } + +init bundlePrice = Model + (Select.init ctShow ctShow Net [Net, Gross]) + (NumberInput.fromFloat bundlePrice) + (NumberInput.fromInt 1) + +getResult model taxGroup = + case (NumberInput.get model.bundlePrice, NumberInput.get model.bundleSize) of + (Just bundlePrice, Just bundleSize) -> + Just <| roundTo 2 <| + if Select.get model.tax == Gross then + (bundlePrice / toFloat bundleSize) / (1 + taxGroup.percentage) + else + bundlePrice / toFloat bundleSize + _ -> + Nothing + + +type Msg + = SetTax String + | SetBundlePrice String + | SetBundleSize String + +update msg model = case msg of + SetTax key -> + { model | tax = Select.update key model.tax } + SetBundlePrice str -> + { model | bundlePrice = NumberInput.update str model.bundlePrice } + SetBundleSize str -> + { model | bundleSize = NumberInput.update str model.bundleSize } + +view model taxGroup = + let + mainPart = + [ text "(" + , input + [ class "formula-input", placeholder "Gebindepreis" + , value <| NumberInput.show model.bundlePrice + , onInput SetBundlePrice + ] + [] + , text " ÷ " + , input + [ class "formula-input", placeholder "Gebindegröße" + , value <| NumberInput.show model.bundleSize + , onInput SetBundleSize + ] + [] + , text ") " + ] + taxPart = + [ text " ÷ " + , input + [ class "formula-input" + , disabled True + , value <| String.fromFloat <| 1 + taxGroup.percentage + ] + [] + ] + resultPart = + [ text " = " + , input + [ class "formula-input" + , disabled True + , value <| Maybe.withDefault "?" <| Maybe.map String.fromFloat <| getResult model taxGroup + ] + [] + ] + in + fieldset [] + [ legend [] [ text "Preisrechner" ] + , div [] <| List.concat <| List.filterMap identity + [ Just mainPart + , if Select.get model.tax == Gross then Just taxPart else Nothing + , Just resultPart + ] + , div [ class "form-input" ] + [ label [ for "calculator-tax" ] [ text "Gebindepreis ist" ] + , Select.view SetTax model.tax + ] + ] + +roundTo places x = toFloat (round <| x * 10 ^ places) / 10 ^ places diff --git a/frontend/Entry.elm b/frontend/Entry.elm index e0a40fe..d0e1bad 100644 --- a/frontend/Entry.elm +++ b/frontend/Entry.elm @@ -10,6 +10,7 @@ import Html exposing (..) import Html.Attributes exposing (..) import Html.Events exposing (..) +import Calculator import NumberInput import Select @@ -90,35 +91,6 @@ type alias Globals = , taxGroups : List TaxGroup } -type CalculatorTax = Net | Gross - -ctToInt ct = case ct of - Gross -> 0 - Net -> 1 - -ctShow ct = case ct of - Gross -> "Brutto" - Net -> "Netto" - -type alias CalculatorModel = - { tax : Select.Model CalculatorTax - , bundlePrice : NumberInput.Model Float - , bundleSize : NumberInput.Model Int - } - -type CalculatorMsg - = SetTax String - | SetBundlePrice String - | SetBundleSize String - -updateCalculator msg model = case msg of - SetTax key -> - { model | tax = Select.update key model.tax } - SetBundlePrice str -> - { model | bundlePrice = NumberInput.update str model.bundlePrice } - SetBundleSize str -> - { model | bundleSize = NumberInput.update str model.bundleSize } - type State = ItemSearch { searchTerm : String @@ -128,7 +100,7 @@ type State { barcode : String , name : String , salesUnits : NumberInput.Model Int - , calculator : CalculatorModel + , calculator : Calculator.Model , netUnitPrice : NumberInput.Model Float , grossUnitPrice : NumberInput.Model Float , group : Select.Model Group @@ -144,7 +116,7 @@ type Msg | SetBarcode String | SetName String | SetSalesUnits String - | CalculatorMsg CalculatorMsg + | CalculatorMsg Calculator.Msg | SetNetUnitPrice String | SetGrossUnitPrice String | SetGroup String @@ -179,11 +151,7 @@ updateState msg globals state = case state of ( ItemEditor { barcode = searchResult.barcode , name = searchResult.name - , calculator = - { tax = Select.init ctShow ctShow Net [Net, Gross] - , bundlePrice = NumberInput.fromFloat searchResult.netUnitPrice - , bundleSize = NumberInput.fromInt 1 - } + , calculator = Calculator.init searchResult.netUnitPrice , netUnitPrice = NumberInput.fromFloat searchResult.netUnitPrice , grossUnitPrice = NumberInput.fromFloat (suggestedGrossPrice searchResult.netUnitPrice taxGroup.percentage) @@ -204,7 +172,7 @@ updateState msg globals state = case state of SetSalesUnits str -> (ItemEditor { model | salesUnits = NumberInput.update str model.salesUnits }, Cmd.none) CalculatorMsg msg_ -> - (ItemEditor { model | calculator = updateCalculator msg_ model.calculator }, Cmd.none) + (ItemEditor { model | calculator = Calculator.update msg_ model.calculator }, Cmd.none) SetNetUnitPrice str -> ( ItemEditor { model | netUnitPrice = NumberInput.update str model.netUnitPrice } , Cmd.none @@ -269,7 +237,7 @@ view { globals, state } = case state of [ label [ for "tax-group" ] [ text "Steuergruppe" ] , Select.view SetTaxGroup model.taxGroup ] - , Html.map CalculatorMsg <| viewCalculator model.calculator (Select.get model.taxGroup) + , Html.map CalculatorMsg <| Calculator.view model.calculator (Select.get model.taxGroup) , div [ class "form-input" ] [ label [ for "net-unit-price" ] [ text "Einkaufspreis (Netto)" ] , input @@ -297,70 +265,8 @@ view { globals, state } = case state of ] ] -viewCalculator model taxGroup = - let - mainPart = - [ text "(" - , input - [ class "formula-input", placeholder "Gebindepreis" - , value <| NumberInput.show model.bundlePrice - , onInput SetBundlePrice - ] - [] - , text " ÷ " - , input - [ class "formula-input", placeholder "Gebindegröße" - , value <| NumberInput.show model.bundleSize - , onInput SetBundleSize - ] - [] - , text ") " - ] - taxPart = - [ text " ÷ " - , input - [ class "formula-input" - , disabled True - , value <| String.fromFloat <| 1 + taxGroup.percentage - ] - [] - ] - resultPart = - [ text " = " - , input - [ class "formula-input" - , disabled True - , value <| Maybe.withDefault "?" <| Maybe.map String.fromFloat <| calculatorResult model taxGroup - ] - [] - ] - in - fieldset [] - [ legend [] [ text "Preisrechner" ] - , div [] <| List.concat <| List.filterMap identity - [ Just mainPart - , if Select.get model.tax == Gross then Just taxPart else Nothing - , Just resultPart - ] - , div [ class "form-input" ] - [ label [ for "calculator-tax" ] [ text "Gebindepreis ist" ] - , Select.view SetTax model.tax - ] - ] - -calculatorResult model taxGroup = - case (NumberInput.get model.bundlePrice, NumberInput.get model.bundleSize) of - (Just bundlePrice, Just bundleSize) -> - Just <| roundTo 2 <| - if Select.get model.tax == Gross then - (bundlePrice / toFloat bundleSize) / (1 + taxGroup.percentage) - else - bundlePrice / toFloat bundleSize - _ -> - Nothing - viewSetCalculatedPriceButton model = - case calculatorResult model.calculator (Select.get model.taxGroup) of + case Calculator.getResult model.calculator (Select.get model.taxGroup) of Nothing -> button [ disabled True ] [ text "Auf ? setzen" ] Just calculatedPrice -> diff --git a/jon/static/entry.js b/jon/static/entry.js index f185616..0de63ed 100644 --- a/jon/static/entry.js +++ b/jon/static/entry.js @@ -10739,21 +10739,12 @@ var $elm$core$Basics$never = function (_v0) { var $elm$browser$Browser$element = _Browser_element; var $elm$core$Platform$Sub$batch = _Platform_batch; var $elm$core$Platform$Sub$none = $elm$core$Platform$Sub$batch(_List_Nil); -var $author$project$Entry$Gross = {$: 'Gross'}; var $author$project$Entry$ItemEditor = function (a) { return {$: 'ItemEditor', a: a}; }; -var $author$project$Entry$Net = {$: 'Net'}; var $author$project$Entry$ReceiveSearchResults = function (a) { return {$: 'ReceiveSearchResults', a: a}; }; -var $author$project$Entry$ctShow = function (ct) { - if (ct.$ === 'Gross') { - return 'Brutto'; - } else { - return 'Netto'; - } -}; var $elm$http$Http$BadStatus_ = F2( function (a, b) { return {$: 'BadStatus_', a: a, b: b}; @@ -11046,11 +11037,37 @@ var $elm$http$Http$get = function (r) { return $elm$http$Http$request( {body: $elm$http$Http$emptyBody, expect: r.expect, headers: _List_Nil, method: 'GET', timeout: $elm$core$Maybe$Nothing, tracker: $elm$core$Maybe$Nothing, url: r.url}); }; +var $author$project$Calculator$Gross = {$: 'Gross'}; +var $author$project$Calculator$Model = F3( + function (tax, bundlePrice, bundleSize) { + return {bundlePrice: bundlePrice, bundleSize: bundleSize, tax: tax}; + }); +var $author$project$Calculator$Net = {$: 'Net'}; +var $author$project$Calculator$ctShow = function (ct) { + if (ct.$ === 'Gross') { + return 'Brutto'; + } else { + return 'Netto'; + } +}; var $author$project$Select$Model = F4( function (identify, show, selected, options) { return {identify: identify, options: options, selected: selected, show: show}; }); var $author$project$Select$init = $author$project$Select$Model; +var $author$project$Calculator$init = function (bundlePrice) { + return A3( + $author$project$Calculator$Model, + A4( + $author$project$Select$init, + $author$project$Calculator$ctShow, + $author$project$Calculator$ctShow, + $author$project$Calculator$Net, + _List_fromArray( + [$author$project$Calculator$Net, $author$project$Calculator$Gross])), + $author$project$NumberInput$fromFloat(bundlePrice), + $author$project$NumberInput$fromInt(1)); +}; var $author$project$Entry$SearchResult = function (barcode) { return function (name) { return function (netUnitPrice) { @@ -11172,7 +11189,7 @@ var $author$project$Select$update = F2( {selected: x}); } }); -var $author$project$Entry$updateCalculator = F2( +var $author$project$Calculator$update = F2( function (msg, model) { switch (msg.$) { case 'SetTax': @@ -11252,17 +11269,7 @@ var $author$project$Entry$updateState = F3( $author$project$Entry$ItemEditor( { barcode: searchResult.barcode, - calculator: { - bundlePrice: $author$project$NumberInput$fromFloat(searchResult.netUnitPrice), - bundleSize: $author$project$NumberInput$fromInt(1), - tax: A4( - $author$project$Select$init, - $author$project$Entry$ctShow, - $author$project$Entry$ctShow, - $author$project$Entry$Net, - _List_fromArray( - [$author$project$Entry$Net, $author$project$Entry$Gross])) - }, + calculator: $author$project$Calculator$init(searchResult.netUnitPrice), grossUnitPrice: $author$project$NumberInput$fromFloat( A2($author$project$Entry$suggestedGrossPrice, searchResult.netUnitPrice, taxGroup.percentage)), group: A4( @@ -11351,7 +11358,7 @@ var $author$project$Entry$updateState = F3( _Utils_update( model, { - calculator: A2($author$project$Entry$updateCalculator, msg_, model.calculator) + calculator: A2($author$project$Calculator$update, msg_, model.calculator) })), $elm$core$Platform$Cmd$none); case 'SetNetUnitPrice': @@ -11562,6 +11569,53 @@ var $elm$html$Html$Attributes$step = function (n) { return A2($elm$html$Html$Attributes$stringProperty, 'step', n); }; var $elm$html$Html$table = _VirtualDom_node('table'); +var $author$project$Calculator$SetBundlePrice = function (a) { + return {$: 'SetBundlePrice', a: a}; +}; +var $author$project$Calculator$SetBundleSize = function (a) { + return {$: 'SetBundleSize', a: a}; +}; +var $author$project$Calculator$SetTax = function (a) { + return {$: 'SetTax', a: a}; +}; +var $author$project$NumberInput$get = function ($) { + return $.value; +}; +var $author$project$Calculator$roundTo = F2( + function (places, x) { + return $elm$core$Basics$round( + x * A2($elm$core$Basics$pow, 10, places)) / A2($elm$core$Basics$pow, 10, places); + }); +var $author$project$Calculator$getResult = F2( + function (model, taxGroup) { + var _v0 = _Utils_Tuple2( + $author$project$NumberInput$get(model.bundlePrice), + $author$project$NumberInput$get(model.bundleSize)); + if ((_v0.a.$ === 'Just') && (_v0.b.$ === 'Just')) { + var bundlePrice = _v0.a.a; + var bundleSize = _v0.b.a; + return $elm$core$Maybe$Just( + A2( + $author$project$Calculator$roundTo, + 2, + _Utils_eq( + $author$project$Select$get(model.tax), + $author$project$Calculator$Gross) ? ((bundlePrice / bundleSize) / (1 + taxGroup.percentage)) : (bundlePrice / bundleSize))); + } else { + return $elm$core$Maybe$Nothing; + } + }); +var $elm$core$Maybe$map = F2( + function (f, maybe) { + if (maybe.$ === 'Just') { + var value = maybe.a; + return $elm$core$Maybe$Just( + f(value)); + } else { + return $elm$core$Maybe$Nothing; + } + }); +var $elm$html$Html$Attributes$placeholder = $elm$html$Html$Attributes$stringProperty('placeholder'); var $elm$html$Html$option = _VirtualDom_node('option'); var $elm$html$Html$select = _VirtualDom_node('select'); var $elm$html$Html$Attributes$selected = $elm$html$Html$Attributes$boolProperty('selected'); @@ -11593,49 +11647,7 @@ var $author$project$Select$view = F2( ]), A2($elm$core$List$map, viewOption, model.options)); }); -var $author$project$Entry$SetBundlePrice = function (a) { - return {$: 'SetBundlePrice', a: a}; -}; -var $author$project$Entry$SetBundleSize = function (a) { - return {$: 'SetBundleSize', a: a}; -}; -var $author$project$Entry$SetTax = function (a) { - return {$: 'SetTax', a: a}; -}; -var $author$project$NumberInput$get = function ($) { - return $.value; -}; -var $author$project$Entry$calculatorResult = F2( - function (model, taxGroup) { - var _v0 = _Utils_Tuple2( - $author$project$NumberInput$get(model.bundlePrice), - $author$project$NumberInput$get(model.bundleSize)); - if ((_v0.a.$ === 'Just') && (_v0.b.$ === 'Just')) { - var bundlePrice = _v0.a.a; - var bundleSize = _v0.b.a; - return $elm$core$Maybe$Just( - A2( - $author$project$Entry$roundTo, - 2, - _Utils_eq( - $author$project$Select$get(model.tax), - $author$project$Entry$Gross) ? ((bundlePrice / bundleSize) / (1 + taxGroup.percentage)) : (bundlePrice / bundleSize))); - } else { - return $elm$core$Maybe$Nothing; - } - }); -var $elm$core$Maybe$map = F2( - function (f, maybe) { - if (maybe.$ === 'Just') { - var value = maybe.a; - return $elm$core$Maybe$Just( - f(value)); - } else { - return $elm$core$Maybe$Nothing; - } - }); -var $elm$html$Html$Attributes$placeholder = $elm$html$Html$Attributes$stringProperty('placeholder'); -var $author$project$Entry$viewCalculator = F2( +var $author$project$Calculator$view = F2( function (model, taxGroup) { var taxPart = _List_fromArray( [ @@ -11667,7 +11679,7 @@ var $author$project$Entry$viewCalculator = F2( A2( $elm$core$Maybe$map, $elm$core$String$fromFloat, - A2($author$project$Entry$calculatorResult, model, taxGroup)))) + A2($author$project$Calculator$getResult, model, taxGroup)))) ]), _List_Nil) ]); @@ -11682,7 +11694,7 @@ var $author$project$Entry$viewCalculator = F2( $elm$html$Html$Attributes$placeholder('Gebindepreis'), $elm$html$Html$Attributes$value( $author$project$NumberInput$show(model.bundlePrice)), - $elm$html$Html$Events$onInput($author$project$Entry$SetBundlePrice) + $elm$html$Html$Events$onInput($author$project$Calculator$SetBundlePrice) ]), _List_Nil), $elm$html$Html$text(' ÷ '), @@ -11694,7 +11706,7 @@ var $author$project$Entry$viewCalculator = F2( $elm$html$Html$Attributes$placeholder('Gebindegröße'), $elm$html$Html$Attributes$value( $author$project$NumberInput$show(model.bundleSize)), - $elm$html$Html$Events$onInput($author$project$Entry$SetBundleSize) + $elm$html$Html$Events$onInput($author$project$Calculator$SetBundleSize) ]), _List_Nil), $elm$html$Html$text(') ') @@ -11723,7 +11735,7 @@ var $author$project$Entry$viewCalculator = F2( $elm$core$Maybe$Just(mainPart), _Utils_eq( $author$project$Select$get(model.tax), - $author$project$Entry$Gross) ? $elm$core$Maybe$Just(taxPart) : $elm$core$Maybe$Nothing, + $author$project$Calculator$Gross) ? $elm$core$Maybe$Just(taxPart) : $elm$core$Maybe$Nothing, $elm$core$Maybe$Just(resultPart) ])))), A2( @@ -11744,7 +11756,7 @@ var $author$project$Entry$viewCalculator = F2( [ $elm$html$Html$text('Gebindepreis ist') ])), - A2($author$project$Select$view, $author$project$Entry$SetTax, model.tax) + A2($author$project$Select$view, $author$project$Calculator$SetTax, model.tax) ])) ])); }); @@ -11851,7 +11863,7 @@ var $author$project$Entry$viewSearchResult = function (model) { }; var $author$project$Entry$viewSetCalculatedPriceButton = function (model) { var _v0 = A2( - $author$project$Entry$calculatorResult, + $author$project$Calculator$getResult, model.calculator, $author$project$Select$get(model.taxGroup)); if (_v0.$ === 'Nothing') { @@ -12151,7 +12163,7 @@ var $author$project$Entry$view = function (_v0) { $elm$html$Html$map, $author$project$Entry$CalculatorMsg, A2( - $author$project$Entry$viewCalculator, + $author$project$Calculator$view, model.calculator, $author$project$Select$get(model.taxGroup))), A2( @@ -12306,4 +12318,4 @@ _Platform_export({'Entry':{'init':$author$project$Entry$main( }, A2($elm$json$Json$Decode$field, 'id', $elm$json$Json$Decode$int)); }, - A2($elm$json$Json$Decode$field, 'percentage', $elm$json$Json$Decode$float))))))({"versions":{"elm":"0.19.1"},"types":{"message":"Entry.Msg","aliases":{"Entry.SearchResult":{"args":[],"type":"{ barcode : String.String, name : String.String, netUnitPrice : Basics.Float, bought : String.String, salesUnits : Basics.Int, available : Basics.Bool, locationName : String.String, locationId : Basics.Int, groupName : String.String, groupId : Basics.Int, taxGroupId : Basics.Int }"}},"unions":{"Entry.Msg":{"args":[],"tags":{"SetSearchTerm":["String.String"],"SubmitSearch":[],"ReceiveSearchResults":["Result.Result Http.Error (List.List Entry.SearchResult)"],"GotoItemEditor":["Entry.SearchResult"],"SetBarcode":["String.String"],"SetName":["String.String"],"SetSalesUnits":["String.String"],"CalculatorMsg":["Entry.CalculatorMsg"],"SetNetUnitPrice":["String.String"],"SetGrossUnitPrice":["String.String"],"SetGroup":["String.String"],"SetLocation":["String.String"],"SetTaxGroup":["String.String"]}},"Basics.Bool":{"args":[],"tags":{"True":[],"False":[]}},"Entry.CalculatorMsg":{"args":[],"tags":{"SetTax":["String.String"],"SetBundlePrice":["String.String"],"SetBundleSize":["String.String"]}},"Http.Error":{"args":[],"tags":{"BadUrl":["String.String"],"Timeout":[],"NetworkError":[],"BadStatus":["Basics.Int"],"BadBody":["String.String"]}},"Basics.Float":{"args":[],"tags":{"Float":[]}},"Basics.Int":{"args":[],"tags":{"Int":[]}},"List.List":{"args":["a"],"tags":{}},"Result.Result":{"args":["error","value"],"tags":{"Ok":["value"],"Err":["error"]}},"String.String":{"args":[],"tags":{"String":[]}}}}})}});}(this)); \ No newline at end of file + A2($elm$json$Json$Decode$field, 'percentage', $elm$json$Json$Decode$float))))))({"versions":{"elm":"0.19.1"},"types":{"message":"Entry.Msg","aliases":{"Entry.SearchResult":{"args":[],"type":"{ barcode : String.String, name : String.String, netUnitPrice : Basics.Float, bought : String.String, salesUnits : Basics.Int, available : Basics.Bool, locationName : String.String, locationId : Basics.Int, groupName : String.String, groupId : Basics.Int, taxGroupId : Basics.Int }"}},"unions":{"Entry.Msg":{"args":[],"tags":{"SetSearchTerm":["String.String"],"SubmitSearch":[],"ReceiveSearchResults":["Result.Result Http.Error (List.List Entry.SearchResult)"],"GotoItemEditor":["Entry.SearchResult"],"SetBarcode":["String.String"],"SetName":["String.String"],"SetSalesUnits":["String.String"],"CalculatorMsg":["Calculator.Msg"],"SetNetUnitPrice":["String.String"],"SetGrossUnitPrice":["String.String"],"SetGroup":["String.String"],"SetLocation":["String.String"],"SetTaxGroup":["String.String"]}},"Basics.Bool":{"args":[],"tags":{"True":[],"False":[]}},"Http.Error":{"args":[],"tags":{"BadUrl":["String.String"],"Timeout":[],"NetworkError":[],"BadStatus":["Basics.Int"],"BadBody":["String.String"]}},"Basics.Float":{"args":[],"tags":{"Float":[]}},"Basics.Int":{"args":[],"tags":{"Int":[]}},"List.List":{"args":["a"],"tags":{}},"Calculator.Msg":{"args":[],"tags":{"SetTax":["String.String"],"SetBundlePrice":["String.String"],"SetBundleSize":["String.String"]}},"Result.Result":{"args":["error","value"],"tags":{"Ok":["value"],"Err":["error"]}},"String.String":{"args":[],"tags":{"String":[]}}}}})}});}(this)); \ No newline at end of file