mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-02-20 11:48:27 -06:00
Expand new transaction form.
This commit is contained in:
parent
e6fe08dd61
commit
211526c032
@ -28,6 +28,7 @@ use FireflyIII\Models\UserGroup;
|
||||
use FireflyIII\Rules\BelongsUserGroup;
|
||||
use FireflyIII\Rules\IsBoolean;
|
||||
use FireflyIII\Rules\IsDateOrTime;
|
||||
use FireflyIII\Rules\IsValidPositiveAmount;
|
||||
use FireflyIII\Support\NullArrayObject;
|
||||
use FireflyIII\Support\Request\AppendsLocationData;
|
||||
use FireflyIII\Support\Request\ChecksLogin;
|
||||
@ -74,7 +75,6 @@ class StoreRequest extends FormRequest
|
||||
'fire_webhooks' => $this->boolean('fire_webhooks', true),
|
||||
'transactions' => $this->getTransactionData(),
|
||||
];
|
||||
// TODO include location and ability to process it.
|
||||
}
|
||||
|
||||
/**
|
||||
@ -107,8 +107,8 @@ class StoreRequest extends FormRequest
|
||||
'transactions.*.foreign_currency_code' => 'min:3|max:51|exists:transaction_currencies,code|nullable',
|
||||
|
||||
// amount
|
||||
'transactions.*.amount' => 'required|numeric|gt:0|max:1000000000',
|
||||
'transactions.*.foreign_amount' => 'numeric|gt:0|max:1000000000',
|
||||
'transactions.*.amount' => ['required', new IsValidPositiveAmount()],
|
||||
'transactions.*.foreign_amount' => ['nullable', new IsValidPositiveAmount()],
|
||||
|
||||
// description
|
||||
'transactions.*.description' => 'nullable|between:1,1000',
|
||||
@ -140,7 +140,8 @@ class StoreRequest extends FormRequest
|
||||
// other interesting fields
|
||||
'transactions.*.reconciled' => [new IsBoolean()],
|
||||
'transactions.*.notes' => 'min:1|max:50000|nullable',
|
||||
'transactions.*.tags' => 'between:0,255',
|
||||
'transactions.*.tags' => 'between:0,1024',
|
||||
'transactions.*.tags*' => 'between:0,1024',
|
||||
|
||||
// meta info fields
|
||||
'transactions.*.internal_reference' => 'min:1|max:255|nullable',
|
||||
@ -166,6 +167,9 @@ class StoreRequest extends FormRequest
|
||||
'transactions.*.due_date' => 'date|nullable',
|
||||
'transactions.*.payment_date' => 'date|nullable',
|
||||
'transactions.*.invoice_date' => 'date|nullable',
|
||||
|
||||
// TODO include location and ability to process it.
|
||||
|
||||
];
|
||||
}
|
||||
|
||||
@ -222,7 +226,7 @@ class StoreRequest extends FormRequest
|
||||
*/
|
||||
foreach ($this->get('transactions') as $transaction) {
|
||||
$object = new NullArrayObject($transaction);
|
||||
$return[] = [
|
||||
$result= [
|
||||
'type' => $this->clearString($object['type']),
|
||||
'date' => $this->dateFromValue($object['date']),
|
||||
'order' => $this->integerFromValue((string)$object['order']),
|
||||
@ -300,6 +304,8 @@ class StoreRequest extends FormRequest
|
||||
'payment_date' => $this->dateFromValue($object['payment_date']),
|
||||
'invoice_date' => $this->dateFromValue($object['invoice_date']),
|
||||
];
|
||||
$result = $this->addFromromTransactionStore($transaction, $result);
|
||||
$return[] = $result;
|
||||
}
|
||||
|
||||
return $return;
|
||||
|
@ -28,6 +28,7 @@ use Carbon\Carbon;
|
||||
use FireflyIII\Exceptions\DuplicateTransactionException;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Location;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
@ -96,7 +97,7 @@ class TransactionJournalFactory
|
||||
{
|
||||
app('log')->debug('Now in TransactionJournalFactory::create()');
|
||||
// convert to special object.
|
||||
$dataObject = new NullArrayObject($data);
|
||||
$dataObject = new NullArrayObject($data);
|
||||
|
||||
app('log')->debug('Start of TransactionJournalFactory::create()');
|
||||
$collection = new Collection();
|
||||
@ -163,7 +164,7 @@ class TransactionJournalFactory
|
||||
|
||||
protected function storeMeta(TransactionJournal $journal, NullArrayObject $data, string $field): void
|
||||
{
|
||||
$set = [
|
||||
$set = [
|
||||
'journal' => $journal,
|
||||
'name' => $field,
|
||||
'data' => (string) ($data[$field] ?? ''),
|
||||
@ -197,14 +198,14 @@ class TransactionJournalFactory
|
||||
$this->errorIfDuplicate($row['import_hash_v2']);
|
||||
|
||||
/** Some basic fields */
|
||||
$type = $this->typeRepository->findTransactionType(null, $row['type']);
|
||||
$carbon = $row['date'] ?? today(config('app.timezone'));
|
||||
$order = $row['order'] ?? 0;
|
||||
$currency = $this->currencyRepository->findCurrency((int) $row['currency_id'], $row['currency_code']);
|
||||
$foreignCurrency = $this->currencyRepository->findCurrencyNull($row['foreign_currency_id'], $row['foreign_currency_code']);
|
||||
$bill = $this->billRepository->findBill((int) $row['bill_id'], $row['bill_name']);
|
||||
$billId = TransactionType::WITHDRAWAL === $type->type && null !== $bill ? $bill->id : null;
|
||||
$description = (string) $row['description'];
|
||||
$type = $this->typeRepository->findTransactionType(null, $row['type']);
|
||||
$carbon = $row['date'] ?? today(config('app.timezone'));
|
||||
$order = $row['order'] ?? 0;
|
||||
$currency = $this->currencyRepository->findCurrency((int) $row['currency_id'], $row['currency_code']);
|
||||
$foreignCurrency = $this->currencyRepository->findCurrencyNull($row['foreign_currency_id'], $row['foreign_currency_code']);
|
||||
$bill = $this->billRepository->findBill((int) $row['bill_id'], $row['bill_name']);
|
||||
$billId = TransactionType::WITHDRAWAL === $type->type && null !== $bill ? $bill->id : null;
|
||||
$description = (string) $row['description'];
|
||||
|
||||
// Manipulate basic fields
|
||||
$carbon->setTimezone(config('app.timezone'));
|
||||
@ -220,7 +221,7 @@ class TransactionJournalFactory
|
||||
}
|
||||
|
||||
/** create or get source and destination accounts */
|
||||
$sourceInfo = [
|
||||
$sourceInfo = [
|
||||
'id' => $row['source_id'],
|
||||
'name' => $row['source_name'],
|
||||
'iban' => $row['source_iban'],
|
||||
@ -229,7 +230,7 @@ class TransactionJournalFactory
|
||||
'currency_id' => $currency->id,
|
||||
];
|
||||
|
||||
$destInfo = [
|
||||
$destInfo = [
|
||||
'id' => $row['destination_id'],
|
||||
'name' => $row['destination_name'],
|
||||
'iban' => $row['destination_iban'],
|
||||
@ -239,8 +240,8 @@ class TransactionJournalFactory
|
||||
];
|
||||
app('log')->debug('Source info:', $sourceInfo);
|
||||
app('log')->debug('Destination info:', $destInfo);
|
||||
$sourceAccount = $this->getAccount($type->type, 'source', $sourceInfo);
|
||||
$destinationAccount = $this->getAccount($type->type, 'destination', $destInfo);
|
||||
$sourceAccount = $this->getAccount($type->type, 'source', $sourceInfo);
|
||||
$destinationAccount = $this->getAccount($type->type, 'destination', $destInfo);
|
||||
app('log')->debug('Done with getAccount(2x)');
|
||||
|
||||
// this is the moment for a reconciliation sanity check (again).
|
||||
@ -248,15 +249,15 @@ class TransactionJournalFactory
|
||||
[$sourceAccount, $destinationAccount] = $this->reconciliationSanityCheck($sourceAccount, $destinationAccount);
|
||||
}
|
||||
|
||||
$currency = $this->getCurrencyByAccount($type->type, $currency, $sourceAccount, $destinationAccount);
|
||||
$foreignCurrency = $this->compareCurrencies($currency, $foreignCurrency);
|
||||
$foreignCurrency = $this->getForeignByAccount($type->type, $foreignCurrency, $destinationAccount);
|
||||
$description = $this->getDescription($description);
|
||||
$currency = $this->getCurrencyByAccount($type->type, $currency, $sourceAccount, $destinationAccount);
|
||||
$foreignCurrency = $this->compareCurrencies($currency, $foreignCurrency);
|
||||
$foreignCurrency = $this->getForeignByAccount($type->type, $foreignCurrency, $destinationAccount);
|
||||
$description = $this->getDescription($description);
|
||||
|
||||
app('log')->debug(sprintf('Date: %s (%s)', $carbon->toW3cString(), $carbon->getTimezone()->getName()));
|
||||
|
||||
/** Create a basic journal. */
|
||||
$journal = TransactionJournal::create(
|
||||
$journal = TransactionJournal::create(
|
||||
[
|
||||
'user_id' => $this->user->id,
|
||||
'user_group_id' => $this->user->user_group_id,
|
||||
@ -273,7 +274,7 @@ class TransactionJournalFactory
|
||||
app('log')->debug(sprintf('Created new journal #%d: "%s"', $journal->id, $journal->description));
|
||||
|
||||
/** Create two transactions. */
|
||||
$transactionFactory = app(TransactionFactory::class);
|
||||
$transactionFactory = app(TransactionFactory::class);
|
||||
$transactionFactory->setUser($this->user);
|
||||
$transactionFactory->setJournal($journal);
|
||||
$transactionFactory->setAccount($sourceAccount);
|
||||
@ -292,7 +293,7 @@ class TransactionJournalFactory
|
||||
}
|
||||
|
||||
/** @var TransactionFactory $transactionFactory */
|
||||
$transactionFactory = app(TransactionFactory::class);
|
||||
$transactionFactory = app(TransactionFactory::class);
|
||||
$transactionFactory->setUser($this->user);
|
||||
$transactionFactory->setJournal($journal);
|
||||
$transactionFactory->setAccount($destinationAccount);
|
||||
@ -310,7 +311,7 @@ class TransactionJournalFactory
|
||||
|
||||
throw new FireflyException($e->getMessage(), 0, $e);
|
||||
}
|
||||
$journal->completed = true;
|
||||
$journal->completed = true;
|
||||
$journal->save();
|
||||
$this->storeBudget($journal, $row);
|
||||
$this->storeCategory($journal, $row);
|
||||
@ -318,10 +319,23 @@ class TransactionJournalFactory
|
||||
$this->storePiggyEvent($journal, $row);
|
||||
$this->storeTags($journal, $row['tags']);
|
||||
$this->storeMetaFields($journal, $row);
|
||||
$this->storeLocation($journal, $row);
|
||||
|
||||
return $journal;
|
||||
}
|
||||
|
||||
private function storeLocation(TransactionJournal $journal, NullArrayObject $data): void
|
||||
{
|
||||
if (true === $data['store_location']) {
|
||||
$location = new Location();
|
||||
$location->longitude = $data['longitude'];
|
||||
$location->latitude = $data['latitude'];
|
||||
$location->zoom_level = $data['zoom_level'];
|
||||
$location->locatable()->associate($journal);
|
||||
$location->save();
|
||||
}
|
||||
}
|
||||
|
||||
private function hashArray(NullArrayObject $row): string
|
||||
{
|
||||
$dataRow = $row->getArrayCopy();
|
||||
@ -334,7 +348,7 @@ class TransactionJournalFactory
|
||||
app('log')->error(sprintf('Could not encode dataRow: %s', $e->getMessage()));
|
||||
$json = microtime();
|
||||
}
|
||||
$hash = hash('sha256', $json);
|
||||
$hash = hash('sha256', $json);
|
||||
app('log')->debug(sprintf('The hash is: %s', $hash), $dataRow);
|
||||
|
||||
return $hash;
|
||||
@ -355,21 +369,17 @@ class TransactionJournalFactory
|
||||
|
||||
/** @var null|TransactionJournalMeta $result */
|
||||
$result = TransactionJournalMeta::withTrashed()
|
||||
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'journal_meta.transaction_journal_id')
|
||||
->whereNotNull('transaction_journals.id')
|
||||
->where('transaction_journals.user_id', $this->user->id)
|
||||
->where('data', json_encode($hash, JSON_THROW_ON_ERROR))
|
||||
->with(['transactionJournal', 'transactionJournal.transactionGroup'])
|
||||
->first()
|
||||
;
|
||||
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'journal_meta.transaction_journal_id')
|
||||
->whereNotNull('transaction_journals.id')
|
||||
->where('transaction_journals.user_id', $this->user->id)
|
||||
->where('data', json_encode($hash, JSON_THROW_ON_ERROR))
|
||||
->with(['transactionJournal', 'transactionJournal.transactionGroup'])
|
||||
->first(['journal_meta.*']);
|
||||
if (null !== $result) {
|
||||
app('log')->warning(sprintf('Found a duplicate in errorIfDuplicate because hash %s is not unique!', $hash));
|
||||
$journal = $result->transactionJournal()->withTrashed()->first();
|
||||
$group = $journal?->transactionGroup()->withTrashed()->first();
|
||||
$groupId = $group?->id;
|
||||
if (null === $group) {
|
||||
$groupId = 0;
|
||||
}
|
||||
$groupId = (int) $group?->id;
|
||||
|
||||
throw new DuplicateTransactionException(sprintf('Duplicate of transaction #%d.', $groupId));
|
||||
}
|
||||
@ -381,18 +391,18 @@ class TransactionJournalFactory
|
||||
private function validateAccounts(NullArrayObject $data): void
|
||||
{
|
||||
app('log')->debug(sprintf('Now in %s', __METHOD__));
|
||||
$transactionType = $data['type'] ?? 'invalid';
|
||||
$transactionType = $data['type'] ?? 'invalid';
|
||||
$this->accountValidator->setUser($this->user);
|
||||
$this->accountValidator->setTransactionType($transactionType);
|
||||
|
||||
// validate source account.
|
||||
$array = [
|
||||
$array = [
|
||||
'id' => null !== $data['source_id'] ? (int) $data['source_id'] : null,
|
||||
'name' => null !== $data['source_name'] ? (string) $data['source_name'] : null,
|
||||
'iban' => null !== $data['source_iban'] ? (string) $data['source_iban'] : null,
|
||||
'number' => null !== $data['source_number'] ? (string) $data['source_number'] : null,
|
||||
];
|
||||
$validSource = $this->accountValidator->validateSource($array);
|
||||
$validSource = $this->accountValidator->validateSource($array);
|
||||
|
||||
// do something with result:
|
||||
if (false === $validSource) {
|
||||
@ -401,7 +411,7 @@ class TransactionJournalFactory
|
||||
app('log')->debug('Source seems valid.');
|
||||
|
||||
// validate destination account
|
||||
$array = [
|
||||
$array = [
|
||||
'id' => null !== $data['destination_id'] ? (int) $data['destination_id'] : null,
|
||||
'name' => null !== $data['destination_name'] ? (string) $data['destination_name'] : null,
|
||||
'iban' => null !== $data['destination_iban'] ? (string) $data['destination_iban'] : null,
|
||||
@ -469,7 +479,7 @@ class TransactionJournalFactory
|
||||
// return user's default:
|
||||
return app('amount')->getDefaultCurrencyByUserGroup($this->user->userGroup);
|
||||
}
|
||||
$result = $preference ?? $currency;
|
||||
$result = $preference ?? $currency;
|
||||
app('log')->debug(sprintf('Currency is now #%d (%s) because of account #%d (%s)', $result->id, $result->code, $account->id, $account->name));
|
||||
|
||||
return $result;
|
||||
|
@ -93,12 +93,14 @@ class Location extends Model
|
||||
return $rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the accounts.
|
||||
*/
|
||||
public function accounts(): MorphMany
|
||||
{
|
||||
return $this->morphMany(Account::class, 'noteable');
|
||||
return $this->morphMany(Account::class, 'locatable');
|
||||
}
|
||||
|
||||
public function transactionJournals(): MorphMany
|
||||
{
|
||||
return $this->morphMany(TransactionJournal::class, 'locatable');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -78,12 +78,12 @@ trait AppendsLocationData
|
||||
$data['latitude'] = null;
|
||||
$data['zoom_level'] = null;
|
||||
|
||||
$longitudeKey = $this->getLocationKey($prefix, 'longitude');
|
||||
$latitudeKey = $this->getLocationKey($prefix, 'latitude');
|
||||
$zoomLevelKey = $this->getLocationKey($prefix, 'zoom_level');
|
||||
$isValidPOST = $this->isValidPost($prefix);
|
||||
$isValidPUT = $this->isValidPUT($prefix);
|
||||
$isValidEmptyPUT = $this->isValidEmptyPUT($prefix);
|
||||
$longitudeKey = $this->getLocationKey($prefix, 'longitude');
|
||||
$latitudeKey = $this->getLocationKey($prefix, 'latitude');
|
||||
$zoomLevelKey = $this->getLocationKey($prefix, 'zoom_level');
|
||||
$isValidPOST = $this->isValidPost($prefix);
|
||||
$isValidPUT = $this->isValidPUT($prefix);
|
||||
$isValidEmptyPUT = $this->isValidEmptyPUT($prefix);
|
||||
|
||||
// for a POST (store), all fields must be present and not NULL.
|
||||
if ($isValidPOST) {
|
||||
@ -119,6 +119,40 @@ trait AppendsLocationData
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $information
|
||||
* @param array $return
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function addFromromTransactionStore(array $information, array $return): array
|
||||
{
|
||||
$return['store_location'] = false;
|
||||
if (true === $information['store_location']) {
|
||||
$long = array_key_exists('longitude', $information) ? $information['longitude'] : null;
|
||||
$lat = array_key_exists('latitude', $information) ? $information['latitude'] : null;
|
||||
if (null !== $long && null !== $lat && $this->validLongitude($long) && $this->validLatitude($lat)) {
|
||||
$return['store_location'] = true;
|
||||
$return['longitude'] = $information['longitude'];
|
||||
$return['latitude'] = $information['latitude'];
|
||||
$return['zoom_level'] = $information['zoom_level'];
|
||||
}
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
private function validLongitude(string $longitude): bool
|
||||
{
|
||||
$number = (float) $longitude;
|
||||
return $number >= -180 && $number <= 180;
|
||||
}
|
||||
|
||||
private function validLatitude(string $latitude): bool
|
||||
{
|
||||
$number = (float) $latitude;
|
||||
return $number >= -90 && $number <= 90;
|
||||
}
|
||||
|
||||
private function getLocationKey(?string $prefix, string $key): string
|
||||
{
|
||||
if (null === $prefix) {
|
||||
@ -213,9 +247,9 @@ trait AppendsLocationData
|
||||
$zoomLevelKey = $this->getLocationKey($prefix, 'zoom_level');
|
||||
|
||||
return (
|
||||
null === $this->get($longitudeKey)
|
||||
&& null === $this->get($latitudeKey)
|
||||
&& null === $this->get($zoomLevelKey))
|
||||
null === $this->get($longitudeKey)
|
||||
&& null === $this->get($latitudeKey)
|
||||
&& null === $this->get($zoomLevelKey))
|
||||
&& (
|
||||
'PUT' === $this->method()
|
||||
|| ('POST' === $this->method() && $this->routeIs('*.update'))
|
||||
|
@ -26,6 +26,7 @@ namespace FireflyIII\Transformers\V2;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Location;
|
||||
use FireflyIII\Models\Note;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
@ -47,18 +48,18 @@ class TransactionGroupTransformer extends AbstractTransformer
|
||||
private TransactionCurrency $default;
|
||||
private array $meta;
|
||||
private array $notes;
|
||||
private array $locations;
|
||||
private array $tags;
|
||||
|
||||
public function collectMetaData(Collection $objects): void
|
||||
{
|
||||
// start with currencies:
|
||||
$currencies = [];
|
||||
$journals = [];
|
||||
$currencies = [];
|
||||
$journals = [];
|
||||
|
||||
/** @var array $object */
|
||||
foreach ($objects as $object) {
|
||||
foreach ($object['sums'] as $sum) {
|
||||
$id = (int) $sum['currency_id'];
|
||||
$id = (int) $sum['currency_id'];
|
||||
$currencies[$id] ??= TransactionCurrency::find($sum['currency_id']);
|
||||
}
|
||||
|
||||
@ -72,7 +73,7 @@ class TransactionGroupTransformer extends AbstractTransformer
|
||||
$this->default = app('amount')->getDefaultCurrency();
|
||||
|
||||
// grab meta for all journals:
|
||||
$meta = TransactionJournalMeta::whereIn('transaction_journal_id', array_keys($journals))->get();
|
||||
$meta = TransactionJournalMeta::whereIn('transaction_journal_id', array_keys($journals))->get();
|
||||
|
||||
/** @var TransactionJournalMeta $entry */
|
||||
foreach ($meta as $entry) {
|
||||
@ -81,7 +82,7 @@ class TransactionGroupTransformer extends AbstractTransformer
|
||||
}
|
||||
|
||||
// grab all notes for all journals:
|
||||
$notes = Note::whereNoteableType(TransactionJournal::class)->whereIn('noteable_id', array_keys($journals))->get();
|
||||
$notes = Note::whereNoteableType(TransactionJournal::class)->whereIn('noteable_id', array_keys($journals))->get();
|
||||
|
||||
/** @var Note $note */
|
||||
foreach ($notes as $note) {
|
||||
@ -89,12 +90,20 @@ class TransactionGroupTransformer extends AbstractTransformer
|
||||
$this->notes[$id] = $note;
|
||||
}
|
||||
|
||||
// grab all locations for all journals:
|
||||
$locations = Location::whereLocatableType(TransactionJournal::class)->whereIn('locatable_id', array_keys($journals))->get();
|
||||
|
||||
/** @var Location $location */
|
||||
foreach ($locations as $location) {
|
||||
$id = $location->locatable_id;
|
||||
$this->locations[$id] = $location;
|
||||
}
|
||||
|
||||
// grab all tags for all journals:
|
||||
$tags = DB::table('tag_transaction_journal')
|
||||
->leftJoin('tags', 'tags.id', 'tag_transaction_journal.tag_id')
|
||||
->whereIn('tag_transaction_journal.transaction_journal_id', array_keys($journals))
|
||||
->get(['tag_transaction_journal.transaction_journal_id', 'tags.tag'])
|
||||
;
|
||||
$tags = DB::table('tag_transaction_journal')
|
||||
->leftJoin('tags', 'tags.id', 'tag_transaction_journal.tag_id')
|
||||
->whereIn('tag_transaction_journal.transaction_journal_id', array_keys($journals))
|
||||
->get(['tag_transaction_journal.transaction_journal_id', 'tags.tag']);
|
||||
|
||||
/** @var \stdClass $tag */
|
||||
foreach ($tags as $tag) {
|
||||
@ -104,7 +113,7 @@ class TransactionGroupTransformer extends AbstractTransformer
|
||||
|
||||
// create converter
|
||||
Log::debug(sprintf('Created new ExchangeRateConverter in %s', __METHOD__));
|
||||
$this->converter = new ExchangeRateConverter();
|
||||
$this->converter = new ExchangeRateConverter();
|
||||
}
|
||||
|
||||
public function transform(array $group): array
|
||||
@ -147,10 +156,10 @@ class TransactionGroupTransformer extends AbstractTransformer
|
||||
*/
|
||||
private function transformTransaction(array $transaction): array
|
||||
{
|
||||
$transaction = new NullArrayObject($transaction);
|
||||
$type = $this->stringFromArray($transaction, 'transaction_type_type', TransactionType::WITHDRAWAL);
|
||||
$journalId = (int) $transaction['transaction_journal_id'];
|
||||
$meta = new NullArrayObject($this->meta[$journalId] ?? []);
|
||||
$transaction = new NullArrayObject($transaction);
|
||||
$type = $this->stringFromArray($transaction, 'transaction_type_type', TransactionType::WITHDRAWAL);
|
||||
$journalId = (int) $transaction['transaction_journal_id'];
|
||||
$meta = new NullArrayObject($this->meta[$journalId] ?? []);
|
||||
|
||||
/**
|
||||
* Convert and use amount:
|
||||
@ -167,6 +176,17 @@ class TransactionGroupTransformer extends AbstractTransformer
|
||||
}
|
||||
$this->converter->summarize();
|
||||
|
||||
$longitude = null;
|
||||
$latitude = null;
|
||||
$zoomLevel = null;
|
||||
if (array_key_exists($journalId, $this->locations)) {
|
||||
/** @var Location $location */
|
||||
$location = $this->locations[$journalId];
|
||||
$latitude = (string) $location->latitude;
|
||||
$longitude = (string) $location->longitude;
|
||||
$zoomLevel = $location->zoom_level;
|
||||
}
|
||||
|
||||
return [
|
||||
'user' => (string) $transaction['user_id'],
|
||||
'user_group' => (string) $transaction['user_group_id'],
|
||||
@ -241,9 +261,9 @@ class TransactionGroupTransformer extends AbstractTransformer
|
||||
'invoice_date' => $this->date($meta['invoice_date']),
|
||||
|
||||
// location data
|
||||
// 'longitude' => $longitude,
|
||||
// 'latitude' => $latitude,
|
||||
// 'zoom_level' => $zoomLevel,
|
||||
'longitude' => $longitude,
|
||||
'latitude' => $latitude,
|
||||
'zoom_level' => $zoomLevel,
|
||||
//
|
||||
// 'has_attachments' => $this->hasAttachments((int) $row['transaction_journal_id']),
|
||||
];
|
||||
|
@ -25,6 +25,8 @@ export default class Preferences {
|
||||
return api.get('/api/v1/preferences/' + name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
getByNameNow(name) {
|
||||
return api.get('/api/v1/preferences/' + name);
|
||||
}
|
||||
|
@ -40,6 +40,10 @@ import L from "leaflet";
|
||||
|
||||
import 'leaflet/dist/leaflet.css';
|
||||
|
||||
// TODO upload attachments to other file
|
||||
// TODO fix two maps, perhaps disconnect from entries entirely.
|
||||
// TODO group title
|
||||
// TODO map location from preferences
|
||||
|
||||
let i18n;
|
||||
|
||||
@ -186,7 +190,7 @@ let transactions = function () {
|
||||
budgets: [],
|
||||
piggyBanks: {},
|
||||
subscriptions: [],
|
||||
dateFields: ['interest_date','book_date','process_date','due_date','payment_date','invoice_date'],
|
||||
dateFields: ['interest_date', 'book_date', 'process_date', 'due_date', 'payment_date', 'invoice_date'],
|
||||
|
||||
foreignAmountEnabled: true,
|
||||
filters: {
|
||||
@ -754,19 +758,41 @@ let transactions = function () {
|
||||
let fieldName;
|
||||
|
||||
// todo add 'was-validated' to form.
|
||||
|
||||
console.log('Now processing errors.');
|
||||
for (const key in data.errors) {
|
||||
if (data.errors.hasOwnProperty(key)) {
|
||||
if (key === 'group_title') {
|
||||
console.log('Handling group title error.');
|
||||
// todo handle group errors.
|
||||
//this.group_title_errors = errors.errors[key];
|
||||
}
|
||||
if (key !== 'group_title') {
|
||||
console.log('Handling errors for ' + key);
|
||||
// lol, the dumbest way to explode "transactions.0.something" ever.
|
||||
transactionIndex = parseInt(key.split('.')[1]);
|
||||
fieldName = key.split('.')[2];
|
||||
console.log('Transaction index: ' + transactionIndex);
|
||||
console.log('Field name: ' + fieldName);
|
||||
console.log('Errors');
|
||||
console.log(data.errors[key]);
|
||||
// set error in this object thing.
|
||||
switch (fieldName) {
|
||||
case 'currency_code':
|
||||
case 'foreign_currency_code':
|
||||
case 'category_name':
|
||||
case 'piggy_bank_id':
|
||||
case 'notes':
|
||||
case 'internal_reference':
|
||||
case 'external_url':
|
||||
case 'latitude':
|
||||
case 'longitude':
|
||||
case 'zoom_level':
|
||||
case 'interest_date':
|
||||
case 'book_date':
|
||||
case 'process_date':
|
||||
case 'due_date':
|
||||
case 'payment_date':
|
||||
case 'invoice_date':
|
||||
case 'amount':
|
||||
case 'date':
|
||||
case 'budget_id':
|
||||
@ -779,6 +805,10 @@ let transactions = function () {
|
||||
case 'source_id':
|
||||
this.entries[transactionIndex].errors.source_account = this.entries[transactionIndex].errors.source_account.concat(data.errors[key]);
|
||||
break;
|
||||
case 'type':
|
||||
// put the error in the description:
|
||||
this.entries[transactionIndex].errors.description = this.entries[transactionIndex].errors.source_account.concat(data.errors[key]);
|
||||
break;
|
||||
case 'destination_name':
|
||||
case 'destination_id':
|
||||
this.entries[transactionIndex].errors.destination_account = this.entries[transactionIndex].errors.destination_account.concat(data.errors[key]);
|
||||
@ -810,6 +840,7 @@ let transactions = function () {
|
||||
server: urls.tag,
|
||||
liveServer: true,
|
||||
clearEnd: true,
|
||||
allowNew: true,
|
||||
notFoundMessage: '(nothing found)',
|
||||
noCache: true,
|
||||
fetchOptions: {
|
||||
@ -819,14 +850,28 @@ let transactions = function () {
|
||||
}
|
||||
});
|
||||
const count = this.entries.length - 1;
|
||||
this.entries[count].map = L.map('mappie').setView([this.latitude, this.longitude], this.zoomLevel);
|
||||
//let map = L.map('location_map_' + count).setView([this.latitude, this.longitude], this.zoomLevel);
|
||||
|
||||
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
maxZoom: 19,
|
||||
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
|
||||
}).addTo(this.entries[count].map);
|
||||
this.entries[count].map.on('click', this.addPointToMap);
|
||||
this.entries[count].map.on('zoomend', this.saveZoomOfMap);
|
||||
// L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
// maxZoom: 19,
|
||||
// attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap '+count+'</a>'
|
||||
// }).addTo(map);
|
||||
// map.on('click', this.addPointToMap);
|
||||
// map.on('zoomend', this.saveZoomOfMap);
|
||||
|
||||
const id = 'location_map_' + count;
|
||||
const map = () => {
|
||||
const el = document.getElementById(id),
|
||||
map = L.map(id).setView([this.latitude, this.longitude], this.zoomLevel)
|
||||
L.tileLayer(
|
||||
'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
{attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap '+count+'</a>'}
|
||||
).addTo(map)
|
||||
map.on('click', this.addPointToMap);
|
||||
map.on('zoomend', this.saveZoomOfMap);
|
||||
return map
|
||||
}
|
||||
this.entries[count].map = map();
|
||||
|
||||
}, 250);
|
||||
|
||||
@ -878,13 +923,6 @@ let transactions = function () {
|
||||
document.querySelector('#form')._x_dataStack[0].$data.entries[index].longitude = e.latlng.lng;
|
||||
document.querySelector('#form')._x_dataStack[0].$data.entries[index].zoomLevel = map.getZoom();
|
||||
}
|
||||
//this.entries[index].hasLocation = true;
|
||||
// map.on('click', function (e) {
|
||||
// if (false === this.hasLocation) {
|
||||
// let marker = new L.marker(e.latlng).addTo(map);
|
||||
// this.hasLocation = true;
|
||||
// }
|
||||
// });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -76,11 +76,43 @@ export function createEmptySplit() {
|
||||
invoice_date: '',
|
||||
|
||||
errors: {
|
||||
'amount': [],
|
||||
'foreign_amount': [],
|
||||
'budget_id': [],
|
||||
'category_name': [],
|
||||
'piggy_bank_id': [],
|
||||
description: [],
|
||||
|
||||
// amount information:
|
||||
amount: [],
|
||||
currency_code: [],
|
||||
foreign_amount: [],
|
||||
foreign_currency_code: [],
|
||||
|
||||
// source and destination
|
||||
source_account: [],
|
||||
destination_account: [],
|
||||
|
||||
// meta data information:
|
||||
budget_id: [],
|
||||
category_name: [],
|
||||
piggy_bank_id: [],
|
||||
bill_id: [],
|
||||
tags: [],
|
||||
notes: [],
|
||||
|
||||
// other meta fields:
|
||||
internal_reference: [],
|
||||
external_url: [],
|
||||
|
||||
// map
|
||||
latitude: [],
|
||||
longitude: [],
|
||||
zoom_level: [],
|
||||
|
||||
// date and time
|
||||
date: [],
|
||||
interest_date: [],
|
||||
book_date: [],
|
||||
process_date: [],
|
||||
due_date: [],
|
||||
payment_date: [],
|
||||
invoice_date: [],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -55,14 +55,24 @@ export function parseFromEntries(entries, transactionType) {
|
||||
current.category_name = entry.category_name;
|
||||
current.piggy_bank_id = entry.piggy_bank_id;
|
||||
current.bill_id = entry.bill_id;
|
||||
current.tags = entry.tags;
|
||||
current.notes = entry.notes;
|
||||
|
||||
// more meta
|
||||
current.internal_reference = entry.internal_reference;
|
||||
current.external_url = entry.external_url;
|
||||
|
||||
// location
|
||||
current.store_location = false;
|
||||
if (entry.hasLocation) {
|
||||
current.store_location = true;
|
||||
current.longitude = entry.longitude.toString();
|
||||
current.latitude = entry.latitude.toString();
|
||||
current.zoom_level = entry.zoomLevel;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// if foreign amount currency code is set:
|
||||
if (typeof entry.foreign_currency_code !== 'undefined' && '' !== entry.foreign_currency_code.toString()) {
|
||||
current.foreign_currency_code = entry.foreign_currency_code;
|
||||
|
@ -343,6 +343,7 @@
|
||||
<select
|
||||
class="form-select ac-tags"
|
||||
:id="'tags_' + index"
|
||||
x-model="transaction.tags"
|
||||
:name="'tags['+index+'][]'"
|
||||
multiple>
|
||||
<option value="">Type a tag...</option>
|
||||
@ -406,12 +407,19 @@
|
||||
<i class="fa-solid fa-link"></i>
|
||||
</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="search"
|
||||
<input type="text"
|
||||
class="form-control"
|
||||
:id="'external_url_' + index"
|
||||
x-model="transaction.external_url"
|
||||
:data-index="index"
|
||||
placeholder="{{ __('firefly.external_url') }}">
|
||||
:class="{'is-invalid': transaction.errors.external_url.length > 0, 'form-control': true}"
|
||||
placeholder="{{ __('firefly.external_url') }}" />
|
||||
<template x-if="transaction.errors.external_url.length > 0">
|
||||
<div class="invalid-feedback"
|
||||
x-text="transaction.errors.external_url[0]">
|
||||
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
@ -420,7 +428,7 @@
|
||||
<i class="fa-solid fa-earth-europe"></i>
|
||||
</label>
|
||||
<div class="col-sm-10">
|
||||
<div id="mappie" style="height:300px;" :data-index="index"></div>
|
||||
<div :id="'location_map_' + index" style="height:300px;" :data-index="index"></div>
|
||||
<span class="muted small">
|
||||
<template x-if="!transaction.hasLocation">
|
||||
<span>Tap the map to add a location</span>
|
||||
|
Loading…
Reference in New Issue
Block a user