From 167124bfa3c621bb420fd683f2fe27514a16ee29 Mon Sep 17 00:00:00 2001 From: "duck." Date: Thu, 3 Apr 2025 08:13:42 +0100 Subject: [PATCH] tariff/octopus: Support non-Direct Debit tariffs (#20306) --- tariff/octopus.go | 43 +++++++++++++------ tariff/octopus/rest/api.go | 8 ++++ tariff/octopus_test.go | 6 ++- .../tariff/octopus-productcode.yaml | 7 +++ 4 files changed, 50 insertions(+), 14 deletions(-) diff --git a/tariff/octopus.go b/tariff/octopus.go index a1d053c17..12acda590 100644 --- a/tariff/octopus.go +++ b/tariff/octopus.go @@ -16,11 +16,12 @@ import ( ) type Octopus struct { - log *util.Logger - region string - productCode string - apikey string - data *util.Monitor[api.Rates] + log *util.Logger + region string + productCode string + apikey string + paymentMethod string + data *util.Monitor[api.Rates] } var _ api.Tariff = (*Octopus)(nil) @@ -34,6 +35,7 @@ func NewOctopusFromConfig(other map[string]interface{}) (api.Tariff, error) { Region string Tariff string // DEPRECATED: use ProductCode ProductCode string + DirectDebit bool ApiKey string } @@ -65,13 +67,18 @@ func NewOctopusFromConfig(other map[string]interface{}) (api.Tariff, error) { return nil, errors.New("invalid apikey format") } } - + paymentMethod := octoRest.RatePaymentMethodDirectDebit + if !cc.DirectDebit { + // Not using Direct Debit, filter by non-Direct Debit tariff entries + paymentMethod = octoRest.RatePaymentMethodNotDirectDebit + } t := &Octopus{ - log: logger, - region: cc.Region, - productCode: cc.ProductCode, - apikey: cc.ApiKey, - data: util.NewMonitor[api.Rates](2 * time.Hour), + log: logger, + region: cc.Region, + productCode: cc.ProductCode, + apikey: cc.ApiKey, + paymentMethod: paymentMethod, + data: util.NewMonitor[api.Rates](2 * time.Hour), } done := make(chan error) @@ -122,9 +129,21 @@ func (t *Octopus) run(done chan error) { data := make(api.Rates, 0, len(res.Results)) for _, r := range res.Results { + if t.paymentMethod != "" && r.PaymentMethod != t.paymentMethod { + // A Payment Method filter is set, and this Tariff entry does not match our filter. + continue + } + // ValidityEnd can be zero (wonderful) which just means that the tariff has no present expected end. + // We need to catch that and set the date to something way in the future. + rateEnd := r.ValidityEnd + if rateEnd.IsZero() { + t.log.DEBUG.Printf("handling rate with indefinite length: %v", r.ValidityStart) + // Currently adds a year from the start date + rateEnd = r.ValidityStart.AddDate(1, 0, 0) + } ar := api.Rate{ Start: r.ValidityStart, - End: r.ValidityEnd, + End: rateEnd, // UnitRates are supplied inclusive of tax, though this could be flipped easily with a config flag. Price: r.PriceInclusiveTax / 1e2, } diff --git a/tariff/octopus/rest/api.go b/tariff/octopus/rest/api.go index a1308edd3..67a38a95f 100644 --- a/tariff/octopus/rest/api.go +++ b/tariff/octopus/rest/api.go @@ -40,9 +40,17 @@ type UnitRates struct { Results []Rate `json:"results"` } +// RatePaymentMethodDirectDebit is set when the rate only applies when the customer is paying with Direct Debit. +const RatePaymentMethodDirectDebit = "DIRECT_DEBIT" + +// RatePaymentMethodNotDirectDebit is set when the rate only applies when the customer is paying with +// any payment means that ISN'T Direct Debit (say, pre-payment meters) +const RatePaymentMethodNotDirectDebit = "NON_DIRECT_DEBIT" + type Rate struct { ValidityStart time.Time `json:"valid_from"` ValidityEnd time.Time `json:"valid_to"` PriceInclusiveTax float64 `json:"value_inc_vat"` PriceExclusiveTax float64 `json:"value_exc_vat"` + PaymentMethod string `json:"payment_method"` } diff --git a/tariff/octopus_test.go b/tariff/octopus_test.go index a65c41cb4..19bbd26a5 100644 --- a/tariff/octopus_test.go +++ b/tariff/octopus_test.go @@ -12,8 +12,9 @@ func TestOctopusConfigParse(t *testing.T) { // This test will start failing if you remove the deprecated "tariff" config var. validTariffConfig := map[string]interface{}{ - "region": "H", - "tariff": "GO-22-03-29", + "region": "H", + "tariff": "GO-22-03-29", + "directDebit": "True", } _, err := NewOctopusFromConfig(validTariffConfig) @@ -22,6 +23,7 @@ func TestOctopusConfigParse(t *testing.T) { validProductCodeConfig := map[string]interface{}{ "region": "H", "productcode": "GO-22-03-29", + "directDebit": "False", } _, err = NewOctopusFromConfig(validProductCodeConfig) diff --git a/templates/definition/tariff/octopus-productcode.yaml b/templates/definition/tariff/octopus-productcode.yaml index 1d5e0b041..b7ff2e98b 100644 --- a/templates/definition/tariff/octopus-productcode.yaml +++ b/templates/definition/tariff/octopus-productcode.yaml @@ -20,7 +20,14 @@ params: help: de: "Die DNO-Region, in der Sie sich befinden. Weitere Informationen: https://www.energy-stats.uk/dno-region-codes-explained/" en: "The DNO region you are located in. More information: https://www.energy-stats.uk/dno-region-codes-explained/" + - name: directDebit + type: bool + default: true + help: + de: "Ich benutze den BACS-Lastschrifttarif." + en: "Use Direct Debit tariff rates." render: | type: octopusenergy productCode: {{ .productCode }} region: {{ .region }} + directDebit: {{ .directDebit }}