From 536d25980fdd3190e23dc91277b530fc52b2edc2 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 26 Oct 2025 09:31:07 +0100 Subject: [PATCH] Fix issues related to #11109 --- .../DestroyController.php | 4 + .../CurrencyExchangeRate/UpdateController.php | 1 - public/v1/js/.gitkeep | 0 .../src/components/exchange-rates/Rates.vue | 150 +++++++++++++----- resources/lang/en_US/validation.php | 1 + 5 files changed, 116 insertions(+), 40 deletions(-) mode change 100644 => 100755 public/v1/js/.gitkeep diff --git a/app/Api/V1/Controllers/Models/CurrencyExchangeRate/DestroyController.php b/app/Api/V1/Controllers/Models/CurrencyExchangeRate/DestroyController.php index 733517a506..27ce2e6330 100644 --- a/app/Api/V1/Controllers/Models/CurrencyExchangeRate/DestroyController.php +++ b/app/Api/V1/Controllers/Models/CurrencyExchangeRate/DestroyController.php @@ -28,6 +28,7 @@ use Carbon\Carbon; use FireflyIII\Api\V1\Controllers\Controller; use FireflyIII\Api\V1\Requests\Models\CurrencyExchangeRate\DestroyRequest; use FireflyIII\Enums\UserRoleEnum; +use FireflyIII\Exceptions\FireflyException; use FireflyIII\Models\CurrencyExchangeRate; use FireflyIII\Models\TransactionCurrency; use FireflyIII\Repositories\ExchangeRate\ExchangeRateRepositoryInterface; @@ -75,6 +76,9 @@ class DestroyController extends Controller if ($exchangeRate instanceof CurrencyExchangeRate) { $this->repository->deleteRate($exchangeRate); } + if (!$exchangeRate instanceof CurrencyExchangeRate) { + throw new FireflyException('Bla'); + } return response()->json([], 204); } diff --git a/app/Api/V1/Controllers/Models/CurrencyExchangeRate/UpdateController.php b/app/Api/V1/Controllers/Models/CurrencyExchangeRate/UpdateController.php index 8326f44c52..19a34d1b5e 100644 --- a/app/Api/V1/Controllers/Models/CurrencyExchangeRate/UpdateController.php +++ b/app/Api/V1/Controllers/Models/CurrencyExchangeRate/UpdateController.php @@ -82,7 +82,6 @@ class UpdateController extends Controller $exchangeRate = $this->repository->updateExchangeRate($exchangeRate, $rate, $date); $transformer = new ExchangeRateTransformer(); - $transformer->setParameters($this->parameters); return response() ->api($this->jsonApiObject(self::RESOURCE_KEY, $exchangeRate, $transformer)) diff --git a/public/v1/js/.gitkeep b/public/v1/js/.gitkeep old mode 100644 new mode 100755 diff --git a/resources/assets/v1/src/components/exchange-rates/Rates.vue b/resources/assets/v1/src/components/exchange-rates/Rates.vue index 0ac13a94ad..169d59336e 100644 --- a/resources/assets/v1/src/components/exchange-rates/Rates.vue +++ b/resources/assets/v1/src/components/exchange-rates/Rates.vue @@ -44,20 +44,29 @@
@@ -168,16 +189,19 @@
- -

+

@@ -217,9 +241,9 @@ export default { mounted() { // get from and to code from URL this.newDate = format(new Date, 'yyyy-MM-dd'); - let parts = window.location.href.split('/'); - this.from_code = parts[parts.length - 2]; - this.to_code = parts[parts.length - 1]; + let parts = window.location.pathname.split('/'); + this.from_code = parts[parts.length - 2].toUpperCase(); + this.to_code = parts[parts.length - 1].toUpperCase(); const params = new Proxy(new URLSearchParams(window.location.search), { get: (searchParams, prop) => searchParams.get(prop), @@ -232,8 +256,8 @@ export default { this.downloadRates(this.page); }, methods: { - submitRate: function(e) { - if(e) e.preventDefault(); + submitRate: function (e) { + if (e) e.preventDefault(); this.posting = true; axios.post("./api/v1/exchange-rates", { @@ -260,33 +284,74 @@ export default { if (0 === parts.length) { return; } + console.log('These are the parts', parts); if ('' !== this.rates[index].rate) { + //console.log('[a] Rate info is', this.rates[index]); this.updating = true; - axios.put("./api/v1/exchange-rates/" + this.rates[index].rate_id, {rate: this.rates[index].rate}) - .then(() => { - this.updating = false; - }); + if (0 === parseInt(this.rates[index].rate_id)) { + console.log('[a] POST, not PUT.'); + axios.post('./api/v1/exchange-rates', + { + from: this.from_code, + to: this.to_code, + rate: this.rates[index].rate, + date: this.rates[index].date_field + }) + .then(() => { + this.updating = false; + }); + } + if (0 !== parseInt(this.rates[index].rate_id)) { + console.log('[a] PUT, not POST.'); + axios.put('./api/v1/exchange-rates/' + this.rates[index].rate_id, {rate: this.rates[index].rate}) + .then(() => { + this.updating = false; + }); + } } if ('' !== this.rates[index].inverse) { + //console.log('[b] Rate info is', this.rates[index]); this.updating = true; - axios.put("./api/v1/exchange-rates/" + this.rates[index].inverse_id, {rate: this.rates[index].inverse}) - .then(() => { - this.updating = false; - }); + if (0 === parseInt(this.rates[index].inverse_id)) { + console.log('[b] POST, not PUT.'); + // post, not put + axios.post('./api/v1/exchange-rates', + { + // remember, this is in reverse. + from: this.to_code, + to: this.from_code, + rate: this.rates[index].inverse, + date: this.rates[index].date_field + }) + .then(() => { + this.updating = false; + }); + } + if (0 !== parseInt(this.rates[index].inverse_id)) { + console.log('[b] PUT, not POST.'); + axios.put('./api/v1/exchange-rates/' + this.rates[index].inverse_id, {rate: this.rates[index].inverse}) + .then(() => { + this.updating = false; + }); + } } }, deleteRate: function (index) { // console.log(this.rates[index].key); let parts = this.spliceKey(this.rates[index].key); + if (0 === parts.length) { return; } - // console.log(parts); - + let rateId = parseInt(this.rates[index].rate_id); + let inverseId = parseInt(this.rates[index].inverse_id); // delete A to B - axios.delete("./api/v1/exchange-rates/" + parts.from + '/' + parts.to + '/' + format(parts.date, 'yyyy-MM-dd')); - // delete B to A. - axios.delete("./api/v1/exchange-rates/" + parts.to + '/' + parts.from + '/' + format(parts.date, 'yyyy-MM-dd')); + if (rateId > 0) { + axios.delete('./api/v1/exchange-rates/' + rateId); + } + if (inverseId > 0) { + axios.delete('./api/v1/exchange-rates/' + inverseId); + } this.rates.splice(index, 1); }, @@ -307,6 +372,7 @@ export default { }; }, downloadCurrencies: function () { + console.log('Now downloading currencies.'); this.loading = true; axios.get("./api/v1/currencies/" + this.from_code).then((response) => { this.from = { @@ -327,31 +393,36 @@ export default { downloadRates: function (page) { this.tempRates = {}; this.loading = true; - axios.get("./api/v1/exchange-rates/" + this.from_code + '/' + this.to_code + '?page=' + page).then((response) => { + console.log('Now downloading rates.', page); + axios.get('./api/v1/exchange-rates/' + this.from_code + '/' + this.to_code + '?page=' + page).then((response) => { for (let i in response.data.data) { if (response.data.data.hasOwnProperty(i)) { + console.log('Downloaded entry #' + i); let current = response.data.data[i]; let date = new Date(current.attributes.date); - let from_code = current.attributes.from_currency_code; - let to_code = current.attributes.to_currency_code; + let from_code = current.attributes.from_currency_code.toUpperCase(); + let to_code = current.attributes.to_currency_code.toUpperCase(); let rate = current.attributes.rate; let inverse = ''; let rate_id = current.id; let inverse_id = '0'; let key = from_code + '_' + to_code + '_' + format(date, 'yyyy-MM-dd'); - // console.log('Key is now "' + key + '"'); + console.log('Key is now "' + key + '"'); // perhaps the returned rate is actually the inverse rate. if (from_code === this.to_code && to_code === this.from_code) { // console.log('Inverse rate found!'); key = to_code + '_' + from_code + '_' + format(date, 'yyyy-MM-dd'); rate = ''; + // new: set rate id to zero. + rate_id = '0'; inverse = current.attributes.rate; inverse_id = current.id; - // console.log('Key updated to "' + key + '"'); + console.log('Key updated to "' + key + '"'); } if (!this.tempRates.hasOwnProperty(key)) { + console.log('New entry stored'); this.tempRates[key] = { key: key, date: date, @@ -374,6 +445,7 @@ export default { this.tempRates[key].rate = rate; this.tempRates[key].rate_id = rate_id; } + console.log('Found exchange rate #' + this.tempRates[key].rate_id + ' with inverse #' + this.tempRates[key].inverse_id); } diff --git a/resources/lang/en_US/validation.php b/resources/lang/en_US/validation.php index f7b27c0da6..f2b03091aa 100644 --- a/resources/lang/en_US/validation.php +++ b/resources/lang/en_US/validation.php @@ -32,6 +32,7 @@ return [ 'webhook_account_info' => 'Cannot deliver account information for budget related webhooks.', 'webhook_transaction_info' => 'Cannot deliver transaction information for budget related webhooks.', 'invalid_account_type' => 'A piggy bank can only be linked to asset accounts and liabilities', + 'unique_currency_code' => 'This currency code is already in use', 'invalid_account_currency' => 'This account does not use the currency you have selected', 'current_amount_too_much' => 'The combined amount in "current_amount" cannot exceed the "target_amount".', 'filter_must_be_in' => 'Filter ":filter" must be one of: :values',