Skip to content

Commit

Permalink
Allow to set a cost by the minute per geo-fence
Browse files Browse the repository at this point in the history
  • Loading branch information
adriankumpf committed May 30, 2020
1 parent a5169de commit a4b2699
Show file tree
Hide file tree
Showing 21 changed files with 813 additions and 558 deletions.
11 changes: 8 additions & 3 deletions lib/teslamate/locations.ex
Original file line number Diff line number Diff line change
Expand Up @@ -203,9 +203,14 @@ defmodule TeslaMate.Locations do
UPDATE charging_processes cp
SET cost = (
SELECT
CASE WHEN g.session_fee IS NULL AND g.cost_per_kwh IS NULL THEN NULL
ELSE COALESCE(g.session_fee, 0) +
COALESCE(g.cost_per_kwh * GREATEST(c.charge_energy_used, c.charge_energy_added), 0)
CASE WHEN g.session_fee IS NULL AND g.cost_per_unit IS NULL THEN
NULL
WHEN g.billing_type = 'per_kwh' THEN
COALESCE(g.session_fee, 0) +
COALESCE(g.cost_per_unit * GREATEST(c.charge_energy_used, c.charge_energy_added), 0)
WHEN g.billing_type = 'per_minute' THEN
COALESCE(g.session_fee, 0) +
COALESCE(g.cost_per_unit * c.duration_min, 0)
END
FROM charging_processes c
JOIN geofences g ON g.id = c.geofence_id
Expand Down
14 changes: 10 additions & 4 deletions lib/teslamate/locations/geo_fence.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,18 @@ defmodule TeslaMate.Locations.GeoFence do

import Ecto.Changeset

defmodule BillingType do
use EctoEnum.Postgres, type: :billing_type, enums: [:per_kwh, :per_minute]
end

schema "geofences" do
field :name, :string
field :latitude, :decimal, read_after_writes: true
field :longitude, :decimal, read_after_writes: true
field :radius, :integer

field :cost_per_kwh, :decimal, read_after_writes: true
field :billing_type, BillingType, read_after_writes: true
field :cost_per_unit, :decimal, read_after_writes: true
field :session_fee, :decimal, read_after_writes: true

timestamps()
Expand All @@ -23,12 +28,13 @@ defmodule TeslaMate.Locations.GeoFence do
:radius,
:latitude,
:longitude,
:cost_per_kwh,
:session_fee
:cost_per_unit,
:session_fee,
:billing_type
])
|> validate_required([:name, :latitude, :longitude, :radius])
|> validate_number(:radius, greater_than: 0, less_than: 5000)
|> validate_number(:cost_per_kwh, greater_than_or_equal_to: 0)
|> validate_number(:cost_per_unit, greater_than_or_equal_to: 0)
|> validate_number(:session_fee, greater_than_or_equal_to: 0)
end
end
23 changes: 22 additions & 1 deletion lib/teslamate/log.ex
Original file line number Diff line number Diff line change
Expand Up @@ -536,7 +536,13 @@ defmodule TeslaMate.Log do
0.0

{%{charge_energy_used: kwh_used, charge_energy_added: kwh_added},
%CP{geofence: %GeoFence{cost_per_kwh: cost_per_kwh, session_fee: session_fee}}} ->
%CP{
geofence: %GeoFence{
billing_type: :per_kwh,
cost_per_unit: cost_per_kwh,
session_fee: session_fee
}
}} ->
if match?(%Decimal{}, kwh_used) or match?(%Decimal{}, kwh_added) do
cost =
with %Decimal{} <- cost_per_kwh do
Expand All @@ -551,6 +557,21 @@ defmodule TeslaMate.Log do
end
end

{%{duration_min: minutes},
%CP{
geofence: %GeoFence{
billing_type: :per_minute,
cost_per_unit: cost_per_minute,
session_fee: session_fee
}
}}
when is_number(minutes) ->
cost = Decimal.mult(minutes, cost_per_minute)

if match?(%Decimal{}, cost) or match?(%Decimal{}, session_fee) do
Decimal.add(session_fee || 0, cost || 0)
end

{_, _} ->
nil
end
Expand Down
11 changes: 9 additions & 2 deletions lib/teslamate_web/live/geofence_live/form.ex
Original file line number Diff line number Diff line change
Expand Up @@ -138,10 +138,17 @@ defmodule TeslaMateWeb.GeoFenceLive.Form do
end

defp show_modal_or_save(%GeoFence{} = geofence, changeset, socket) do
has_cost = geofence.session_fee != nil or geofence.cost_per_kwh != nil
has_cost = geofence.session_fee != nil or geofence.cost_per_unit != nil

position_or_cost_changed =
has_changed?(changeset, [:cost_per_kwh, :session_fee, :latitude, :longitude, :radius])
has_changed?(changeset, [
:cost_per_unit,
:session_fee,
:billing_type,
:latitude,
:longitude,
:radius
])

with true <- has_cost and position_or_cost_changed,
n when n > 0 <- Locations.count_charging_processes_without_costs(geofence) do
Expand Down
21 changes: 13 additions & 8 deletions lib/teslamate_web/live/geofence_live/form.html.leex
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,23 @@

<div class="field is-horizontal mt-20">
<div class="field-label is-normal">
<%= label class: "label" do gettext("Cost per kWh") end %>
<%= label class: "label" do gettext("Cost") end %>
</div>
<div class="field-body">
<div class="field">
<div class="control">
<%= text_input f, :cost_per_kwh, class: "input",

<div class="field has-addons">
<p class="control">
<span class="select">
<%= select f, :billing_type, [{gettext("Per kWh"), :per_kwh}, {gettext("Per Minute"), :per_minute}] %>
</span>
</p>
<p class="control is-expanded">
<%= text_input f, :cost_per_unit, class: "input",
type: :number, inputmode: :decimal, min: 0.0, step: 0.0001,
placeholder: "0.00"
%>
</div>
placeholder: "0.00" %>
</p>
<%= if @show_errors do %>
<p class="help is-danger"><%= error_tag(f, :cost_per_kwh) %></p>
<p class="help is-danger"><%= error_tag(f, :cost_per_unit) %></p>
<% end %>
</div>
</div>
Expand Down
49 changes: 26 additions & 23 deletions priv/gettext/da/LC_MESSAGES/default.po
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,13 @@ msgid "Units"
msgstr "Enheder"

#, elixir-format
#: lib/teslamate_web/live/charge_live/cost.html.leex:119
#: lib/teslamate_web/live/geofence_live/form.html.leex:100
#: lib/teslamate_web/live/charge_live/cost.html.leex:131
#: lib/teslamate_web/live/geofence_live/form.html.leex:105
msgid "Back"
msgstr "Tilbage"

#, elixir-format
#: lib/teslamate_web/live/geofence_live/form.ex:197
#: lib/teslamate_web/live/geofence_live/form.ex:204
msgid "Geo-fence \"%{name}\" created"
msgstr "Geografisk afgrænsning \"%{name}\" oprettet"

Expand Down Expand Up @@ -166,14 +166,14 @@ msgid "Radius"
msgstr "Radius"

#, elixir-format
#: lib/teslamate_web/live/charge_live/cost.html.leex:122
#: lib/teslamate_web/live/geofence_live/form.html.leex:103
#: lib/teslamate_web/live/charge_live/cost.html.leex:134
#: lib/teslamate_web/live/geofence_live/form.html.leex:108
msgid "Save"
msgstr "Gem"

#, elixir-format
#: lib/teslamate_web/live/charge_live/cost.html.leex:123
#: lib/teslamate_web/live/geofence_live/form.html.leex:103 lib/teslamate_web/live/signin_live/index.html.leex:33
#: lib/teslamate_web/live/charge_live/cost.html.leex:135
#: lib/teslamate_web/live/geofence_live/form.html.leex:108 lib/teslamate_web/live/signin_live/index.html.leex:33
msgid "Saving..."
msgstr "Gemmer..."

Expand Down Expand Up @@ -369,7 +369,7 @@ msgid "Sleep Mode"
msgstr "Dvaletilstand"

#, elixir-format
#: lib/teslamate_web/live/geofence_live/form.ex:198
#: lib/teslamate_web/live/geofence_live/form.ex:205
msgid "Geo-fence \"%{name}\" updated"
msgstr "Geografisk afgrænsning \"%{name}\" opdateret"

Expand Down Expand Up @@ -400,17 +400,18 @@ msgid "Charge Cost"
msgstr "Opladningspris"

#, elixir-format
#: lib/teslamate_web/live/charge_live/cost.html.leex:94
#: lib/teslamate_web/live/charge_live/cost.html.leex:103
#: lib/teslamate_web/live/geofence_live/form.html.leex:59
msgid "Cost"
msgstr "Pris"

#, elixir-format
#: lib/teslamate_web/live/charge_live/cost.html.leex:107
#: lib/teslamate_web/live/charge_live/cost.html.leex:119
msgid "Enter charge cost"
msgstr "Indtast pris for opladning"

#, elixir-format
#: lib/teslamate_web/live/charge_live/cost.ex:68
#: lib/teslamate_web/live/charge_live/cost.ex:87
msgid "Saved!"
msgstr "Gemt!"

Expand Down Expand Up @@ -478,11 +479,6 @@ msgstr "Log ind"
msgid "Email address"
msgstr "Emailadresse"

#, elixir-format
#: lib/teslamate_web/live/geofence_live/form.html.leex:59
msgid "Cost per kWh"
msgstr "Pris per kWh"

#, elixir-format
#: lib/teslamate_web/live/settings_live/index.html.leex:92
msgid "Charge cost"
Expand All @@ -499,7 +495,7 @@ msgid "General Settings"
msgstr "Basale indstillinger"

#, elixir-format
#: lib/teslamate_web/live/geofence_live/form.html.leex:78
#: lib/teslamate_web/live/geofence_live/form.html.leex:83
msgid "Session fee"
msgstr "Afgift per opladning"

Expand All @@ -509,34 +505,35 @@ msgid "Doors open"
msgstr "Døre åbne"

#, elixir-format
#: lib/teslamate_web/live/charge_live/cost.html.leex:100
#: lib/teslamate_web/live/charge_live/cost.html.leex:111
#: lib/teslamate_web/live/geofence_live/form.html.leex:66
msgid "Per kWh"
msgstr "Per kWh"

#, elixir-format
#: lib/teslamate_web/live/charge_live/cost.html.leex:100
#: lib/teslamate_web/live/charge_live/cost.html.leex:110
msgid "Total"
msgstr "Total"

#, elixir-format
#: lib/teslamate_web/live/geofence_live/form.html.leex:120
#: lib/teslamate_web/live/geofence_live/form.html.leex:125
msgid "There is <strong>%{n} charging session</strong> at this location for which no costs have been added yet."
msgid_plural "There are <strong>%{n} charging sessions</strong> at this location for which no costs have been added yet."
msgstr[0] "Der er <strong>%{n} opladning</strong> på dette sted der ikke er angivet en pris for endnu."
msgstr[1] "Der er <strong>%{n} opladninger</strong> på dette sted der ikke er angivet en pris for endnu."

#, elixir-format
#: lib/teslamate_web/live/geofence_live/form.html.leex:129
#: lib/teslamate_web/live/geofence_live/form.html.leex:134
msgid "Add costs retroactively"
msgstr "Tilføj pris med tilbagevirkning"

#, elixir-format
#: lib/teslamate_web/live/geofence_live/form.html.leex:114
#: lib/teslamate_web/live/geofence_live/form.html.leex:119
msgid "Charging Costs"
msgstr "Udgifter til opladning"

#, elixir-format
#: lib/teslamate_web/live/geofence_live/form.html.leex:128
#: lib/teslamate_web/live/geofence_live/form.html.leex:133
msgid "Continue"
msgstr "Fortsæt"

Expand Down Expand Up @@ -575,3 +572,9 @@ msgstr "Døre er åbne"
#: lib/teslamate_web/live/car_live/summary.ex:136
msgid "Trunk is open"
msgstr "Bagklap åben"

#, elixir-format
#: lib/teslamate_web/live/charge_live/cost.html.leex:112
#: lib/teslamate_web/live/geofence_live/form.html.leex:66
msgid "Per Minute"
msgstr ""
Loading

0 comments on commit a4b2699

Please sign in to comment.