mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-10-15 00:27:30 +00:00
Allow sending of webhooks from budget limit store.
This commit is contained in:
@@ -67,26 +67,27 @@ class StoreController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function store(StoreRequest $request, Budget $budget): JsonResponse
|
public function store(StoreRequest $request, Budget $budget): JsonResponse
|
||||||
{
|
{
|
||||||
$data = $request->getAll();
|
$data = $request->getAll();
|
||||||
$data['start_date'] = $data['start'];
|
$data['start_date'] = $data['start'];
|
||||||
$data['end_date'] = $data['end'];
|
$data['end_date'] = $data['end'];
|
||||||
$data['budget_id'] = $budget->id;
|
$data['fire_webhooks'] = $data['fire_webhooks'] ?? true;
|
||||||
|
$data['budget_id'] = $budget->id;
|
||||||
|
|
||||||
$budgetLimit = $this->blRepository->store($data);
|
$budgetLimit = $this->blRepository->store($data);
|
||||||
$manager = $this->getManager();
|
$manager = $this->getManager();
|
||||||
|
|
||||||
// enrich
|
// enrich
|
||||||
/** @var User $admin */
|
/** @var User $admin */
|
||||||
$admin = auth()->user();
|
$admin = auth()->user();
|
||||||
$enrichment = new BudgetLimitEnrichment();
|
$enrichment = new BudgetLimitEnrichment();
|
||||||
$enrichment->setUser($admin);
|
$enrichment->setUser($admin);
|
||||||
$budgetLimit = $enrichment->enrichSingle($budgetLimit);
|
$budgetLimit = $enrichment->enrichSingle($budgetLimit);
|
||||||
|
|
||||||
/** @var BudgetLimitTransformer $transformer */
|
/** @var BudgetLimitTransformer $transformer */
|
||||||
$transformer = app(BudgetLimitTransformer::class);
|
$transformer = app(BudgetLimitTransformer::class);
|
||||||
$transformer->setParameters($this->parameters);
|
$transformer->setParameters($this->parameters);
|
||||||
|
|
||||||
$resource = new Item($budgetLimit, $transformer, 'budget_limits');
|
$resource = new Item($budgetLimit, $transformer, 'budget_limits');
|
||||||
|
|
||||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
||||||
}
|
}
|
||||||
|
@@ -24,10 +24,18 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace FireflyIII\Api\V1\Requests\Models\BudgetLimit;
|
namespace FireflyIII\Api\V1\Requests\Models\BudgetLimit;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use FireflyIII\Exceptions\FireflyException;
|
||||||
|
use FireflyIII\Factory\TransactionCurrencyFactory;
|
||||||
|
use FireflyIII\Models\Budget;
|
||||||
|
use FireflyIII\Rules\IsBoolean;
|
||||||
use FireflyIII\Rules\IsValidPositiveAmount;
|
use FireflyIII\Rules\IsValidPositiveAmount;
|
||||||
|
use FireflyIII\Support\Facades\Amount;
|
||||||
use FireflyIII\Support\Request\ChecksLogin;
|
use FireflyIII\Support\Request\ChecksLogin;
|
||||||
use FireflyIII\Support\Request\ConvertsDataTypes;
|
use FireflyIII\Support\Request\ConvertsDataTypes;
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Validation\Validator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class StoreRequest
|
* Class StoreRequest
|
||||||
@@ -49,6 +57,9 @@ class StoreRequest extends FormRequest
|
|||||||
'currency_id' => $this->convertInteger('currency_id'),
|
'currency_id' => $this->convertInteger('currency_id'),
|
||||||
'currency_code' => $this->convertString('currency_code'),
|
'currency_code' => $this->convertString('currency_code'),
|
||||||
'notes' => $this->stringWithNewlines('notes'),
|
'notes' => $this->stringWithNewlines('notes'),
|
||||||
|
|
||||||
|
// for webhooks:
|
||||||
|
'fire_webhooks' => $this->boolean('fire_webhooks', true),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,6 +75,53 @@ class StoreRequest extends FormRequest
|
|||||||
'currency_id' => 'numeric|exists:transaction_currencies,id',
|
'currency_id' => 'numeric|exists:transaction_currencies,id',
|
||||||
'currency_code' => 'min:3|max:51|exists:transaction_currencies,code',
|
'currency_code' => 'min:3|max:51|exists:transaction_currencies,code',
|
||||||
'notes' => 'nullable|min:0|max:32768',
|
'notes' => 'nullable|min:0|max:32768',
|
||||||
|
|
||||||
|
// webhooks
|
||||||
|
'fire_webhooks' => [new IsBoolean()],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure the validator instance.
|
||||||
|
*/
|
||||||
|
public function withValidator(Validator $validator): void
|
||||||
|
{
|
||||||
|
$budget = $this->route()->parameter('budget');
|
||||||
|
$validator->after(
|
||||||
|
static function (Validator $validator) use ($budget): void {
|
||||||
|
if(0 !== count($validator->failed())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$data = $validator->getData();
|
||||||
|
|
||||||
|
// if no currency has been provided, use the user's default currency:
|
||||||
|
/** @var TransactionCurrencyFactory $factory */
|
||||||
|
$factory = app(TransactionCurrencyFactory::class);
|
||||||
|
$currency = $factory->find($data['currency_id'] ?? null, $data['currency_code'] ?? null);
|
||||||
|
if (null === $currency) {
|
||||||
|
$currency = Amount::getPrimaryCurrency();
|
||||||
|
}
|
||||||
|
$currency->enabled = true;
|
||||||
|
$currency->save();
|
||||||
|
|
||||||
|
// validator already concluded start and end are valid dates:
|
||||||
|
$start = Carbon::parse($data['start'], config('app.timezone'));
|
||||||
|
$end = Carbon::parse($data['end'], config('app.timezone'));
|
||||||
|
|
||||||
|
// find limit with same date range and currency.
|
||||||
|
$limit = $budget->budgetlimits()
|
||||||
|
->where('budget_limits.start_date', $start->format('Y-m-d'))
|
||||||
|
->where('budget_limits.end_date', $end->format('Y-m-d'))
|
||||||
|
->where('budget_limits.transaction_currency_id', $currency->id)
|
||||||
|
->first(['budget_limits.*'])
|
||||||
|
;
|
||||||
|
if(null !== $limit) {
|
||||||
|
$validator->errors()->add('start', trans('validation.limit_exists'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if ($validator->fails()) {
|
||||||
|
Log::channel('audit')->error(sprintf('Validation errors in %s', self::class), $validator->errors()->toArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -31,6 +31,7 @@ use FireflyIII\Models\BudgetLimit;
|
|||||||
use FireflyIII\Support\Facades\Amount;
|
use FireflyIII\Support\Facades\Amount;
|
||||||
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
|
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
|
||||||
use FireflyIII\Support\Observers\RecalculatesAvailableBudgetsTrait;
|
use FireflyIII\Support\Observers\RecalculatesAvailableBudgetsTrait;
|
||||||
|
use FireflyIII\Support\Singleton\PreferencesSingleton;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
@@ -44,17 +45,24 @@ class BudgetLimitObserver
|
|||||||
$this->updatePrimaryCurrencyAmount($budgetLimit);
|
$this->updatePrimaryCurrencyAmount($budgetLimit);
|
||||||
$this->updateAvailableBudget($budgetLimit);
|
$this->updateAvailableBudget($budgetLimit);
|
||||||
|
|
||||||
$user = $budgetLimit->budget->user;
|
|
||||||
|
|
||||||
/** @var MessageGeneratorInterface $engine */
|
// this is a lame trick to communicate with the observer.
|
||||||
$engine = app(MessageGeneratorInterface::class);
|
$singleton = PreferencesSingleton::getInstance();
|
||||||
$engine->setUser($user);
|
|
||||||
$engine->setObjects(new Collection()->push($budgetLimit));
|
|
||||||
$engine->setTrigger(WebhookTrigger::STORE_UPDATE_BUDGET_LIMIT);
|
|
||||||
$engine->generateMessages();
|
|
||||||
|
|
||||||
Log::debug(sprintf('send event RequestedSendWebhookMessages from %s', __METHOD__));
|
if (true === $singleton->getPreference('fire_webhooks_bl_store')) {
|
||||||
event(new RequestedSendWebhookMessages());
|
|
||||||
|
$user = $budgetLimit->budget->user;
|
||||||
|
|
||||||
|
/** @var MessageGeneratorInterface $engine */
|
||||||
|
$engine = app(MessageGeneratorInterface::class);
|
||||||
|
$engine->setUser($user);
|
||||||
|
$engine->setObjects(new Collection()->push($budgetLimit));
|
||||||
|
$engine->setTrigger(WebhookTrigger::STORE_UPDATE_BUDGET_LIMIT);
|
||||||
|
$engine->generateMessages();
|
||||||
|
|
||||||
|
Log::debug(sprintf('send event RequestedSendWebhookMessages from %s', __METHOD__));
|
||||||
|
event(new RequestedSendWebhookMessages());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function updatePrimaryCurrencyAmount(BudgetLimit $budgetLimit): void
|
private function updatePrimaryCurrencyAmount(BudgetLimit $budgetLimit): void
|
||||||
|
@@ -31,8 +31,10 @@ use FireflyIII\Models\Budget;
|
|||||||
use FireflyIII\Models\BudgetLimit;
|
use FireflyIII\Models\BudgetLimit;
|
||||||
use FireflyIII\Models\Note;
|
use FireflyIII\Models\Note;
|
||||||
use FireflyIII\Models\TransactionCurrency;
|
use FireflyIII\Models\TransactionCurrency;
|
||||||
|
use FireflyIII\Support\Facades\Amount;
|
||||||
use FireflyIII\Support\Repositories\UserGroup\UserGroupInterface;
|
use FireflyIII\Support\Repositories\UserGroup\UserGroupInterface;
|
||||||
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
|
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
|
||||||
|
use FireflyIII\Support\Singleton\PreferencesSingleton;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
@@ -271,7 +273,7 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup
|
|||||||
$factory = app(TransactionCurrencyFactory::class);
|
$factory = app(TransactionCurrencyFactory::class);
|
||||||
$currency = $factory->find($data['currency_id'] ?? null, $data['currency_code'] ?? null);
|
$currency = $factory->find($data['currency_id'] ?? null, $data['currency_code'] ?? null);
|
||||||
if (null === $currency) {
|
if (null === $currency) {
|
||||||
$currency = app('amount')->getPrimaryCurrencyByUserGroup($this->user->userGroup);
|
$currency = Amount::getPrimaryCurrencyByUserGroup($this->user->userGroup);
|
||||||
}
|
}
|
||||||
$currency->enabled = true;
|
$currency->enabled = true;
|
||||||
$currency->save();
|
$currency->save();
|
||||||
@@ -293,7 +295,11 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup
|
|||||||
if (null !== $limit) {
|
if (null !== $limit) {
|
||||||
throw new FireflyException('200027: Budget limit already exists.');
|
throw new FireflyException('200027: Budget limit already exists.');
|
||||||
}
|
}
|
||||||
app('log')->debug('No existing budget limit, create a new one');
|
Log::debug('No existing budget limit, create a new one');
|
||||||
|
|
||||||
|
// this is a lame trick to communicate with the observer.
|
||||||
|
$singleton = PreferencesSingleton::getInstance();
|
||||||
|
$singleton->setPreference('fire_webhooks_bl_store', $data['fire_webhooks'] ?? true);
|
||||||
|
|
||||||
// or create one and return it.
|
// or create one and return it.
|
||||||
$limit = new BudgetLimit();
|
$limit = new BudgetLimit();
|
||||||
@@ -309,7 +315,7 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup
|
|||||||
$this->setNoteText($limit, $noteText);
|
$this->setNoteText($limit, $noteText);
|
||||||
}
|
}
|
||||||
|
|
||||||
app('log')->debug(sprintf('Created new budget limit with ID #%d and amount %s', $limit->id, $data['amount']));
|
Log::debug(sprintf('Created new budget limit with ID #%d and amount %s', $limit->id, $data['amount']));
|
||||||
|
|
||||||
return $limit;
|
return $limit;
|
||||||
}
|
}
|
||||||
@@ -393,7 +399,7 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup
|
|||||||
->where('budget_limits.end_date', $end->format('Y-m-d 00:00:00'))
|
->where('budget_limits.end_date', $end->format('Y-m-d 00:00:00'))
|
||||||
->count('budget_limits.*')
|
->count('budget_limits.*')
|
||||||
;
|
;
|
||||||
app('log')->debug(sprintf('Found %d budget limits.', $limits));
|
Log::debug(sprintf('Found %d budget limits.', $limits));
|
||||||
|
|
||||||
// there might be a budget limit for these dates:
|
// there might be a budget limit for these dates:
|
||||||
/** @var null|BudgetLimit $limit */
|
/** @var null|BudgetLimit $limit */
|
||||||
@@ -405,7 +411,7 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup
|
|||||||
|
|
||||||
// if more than 1 limit found, delete the others:
|
// if more than 1 limit found, delete the others:
|
||||||
if ($limits > 1 && null !== $limit) {
|
if ($limits > 1 && null !== $limit) {
|
||||||
app('log')->debug(sprintf('Found more than 1, delete all except #%d', $limit->id));
|
Log::debug(sprintf('Found more than 1, delete all except #%d', $limit->id));
|
||||||
$budget->budgetlimits()
|
$budget->budgetlimits()
|
||||||
->where('budget_limits.start_date', $start->format('Y-m-d 00:00:00'))
|
->where('budget_limits.start_date', $start->format('Y-m-d 00:00:00'))
|
||||||
->where('budget_limits.end_date', $end->format('Y-m-d 00:00:00'))
|
->where('budget_limits.end_date', $end->format('Y-m-d 00:00:00'))
|
||||||
@@ -417,20 +423,20 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup
|
|||||||
// Returns 0 if the two operands are equal,
|
// Returns 0 if the two operands are equal,
|
||||||
// 1 if the left_operand is larger than the right_operand, -1 otherwise.
|
// 1 if the left_operand is larger than the right_operand, -1 otherwise.
|
||||||
if (null !== $limit && bccomp($amount, '0') <= 0) {
|
if (null !== $limit && bccomp($amount, '0') <= 0) {
|
||||||
app('log')->debug(sprintf('%s is zero, delete budget limit #%d', $amount, $limit->id));
|
Log::debug(sprintf('%s is zero, delete budget limit #%d', $amount, $limit->id));
|
||||||
$limit->delete();
|
$limit->delete();
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
// update if exists:
|
// update if exists:
|
||||||
if (null !== $limit) {
|
if (null !== $limit) {
|
||||||
app('log')->debug(sprintf('Existing budget limit is #%d, update this to amount %s', $limit->id, $amount));
|
Log::debug(sprintf('Existing budget limit is #%d, update this to amount %s', $limit->id, $amount));
|
||||||
$limit->amount = $amount;
|
$limit->amount = $amount;
|
||||||
$limit->save();
|
$limit->save();
|
||||||
|
|
||||||
return $limit;
|
return $limit;
|
||||||
}
|
}
|
||||||
app('log')->debug('No existing budget limit, create a new one');
|
Log::debug('No existing budget limit, create a new one');
|
||||||
// or create one and return it.
|
// or create one and return it.
|
||||||
$limit = new BudgetLimit();
|
$limit = new BudgetLimit();
|
||||||
$limit->budget()->associate($budget);
|
$limit->budget()->associate($budget);
|
||||||
@@ -440,7 +446,7 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup
|
|||||||
$limit->end_date_tz = $end->format('e');
|
$limit->end_date_tz = $end->format('e');
|
||||||
$limit->amount = $amount;
|
$limit->amount = $amount;
|
||||||
$limit->save();
|
$limit->save();
|
||||||
app('log')->debug(sprintf('Created new budget limit with ID #%d and amount %s', $limit->id, $amount));
|
Log::debug(sprintf('Created new budget limit with ID #%d and amount %s', $limit->id, $amount));
|
||||||
|
|
||||||
return $limit;
|
return $limit;
|
||||||
}
|
}
|
||||||
|
@@ -24,6 +24,7 @@
|
|||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
'limit_exists' => 'There is already a budget limit (amount) for this budget and currency in the given period.',
|
||||||
'invalid_sort_instruction' => 'The sort instruction is invalid for an object of type ":object".',
|
'invalid_sort_instruction' => 'The sort instruction is invalid for an object of type ":object".',
|
||||||
'invalid_sort_instruction_index' => 'The sort instruction at index #:index is invalid for an object of type ":object".',
|
'invalid_sort_instruction_index' => 'The sort instruction at index #:index is invalid for an object of type ":object".',
|
||||||
'no_sort_instructions' => 'There are no sort instructions defined for an object of type ":object".',
|
'no_sort_instructions' => 'There are no sort instructions defined for an object of type ":object".',
|
||||||
|
Reference in New Issue
Block a user