Merge branch 'master' into title-subheading

This commit is contained in:
Cüneyt Şentürk 2023-07-19 14:43:19 +03:00 committed by GitHub
commit 797ee71f6b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
628 changed files with 65799 additions and 80258 deletions

View File

@ -1,10 +1,11 @@
name: Tests name: Tests
on: on:
push: push:
pull_request: pull_request:
schedule: schedule:
- cron: '0 0 * * *' - cron: '0 0 * * *'
workflow_dispatch:
jobs: jobs:
tests: tests:
@ -15,11 +16,11 @@ jobs:
strategy: strategy:
matrix: matrix:
php: ['8.0', '8.1'] php: ['8.1', '8.2']
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v2 uses: actions/checkout@v3
- name: Cache Composer - name: Cache Composer
uses: actions/cache@v1 uses: actions/cache@v1

View File

@ -3,24 +3,24 @@
[![Release](https://img.shields.io/github/v/release/akaunting/akaunting?label=release)](https://github.com/akaunting/akaunting/releases) [![Release](https://img.shields.io/github/v/release/akaunting/akaunting?label=release)](https://github.com/akaunting/akaunting/releases)
![Downloads](https://img.shields.io/github/downloads/akaunting/akaunting/total?label=downloads) ![Downloads](https://img.shields.io/github/downloads/akaunting/akaunting/total?label=downloads)
[![Translations](https://badges.crowdin.net/akaunting/localized.svg)](https://crowdin.com/project/akaunting) [![Translations](https://badges.crowdin.net/akaunting/localized.svg)](https://crowdin.com/project/akaunting)
[![Tests](https://img.shields.io/github/workflow/status/akaunting/akaunting/Tests?label=tests)](https://github.com/akaunting/akaunting/actions) [![Tests](https://img.shields.io/github/actions/workflow/status/akaunting/akaunting/tests.yml?label=tests)](https://github.com/akaunting/akaunting/actions)
[![License](https://img.shields.io/github/license/akaunting/akaunting?label=license)](LICENSE.txt) [![License](https://img.shields.io/github/license/akaunting/akaunting?label=license)](LICENSE.txt)
Akaunting is a free, open source and online accounting software designed for small businesses and freelancers. It is built with modern technologies such as Laravel, VueJS, Tailwind, RESTful API etc. Thanks to its modular structure, Akaunting provides an awesome App Store for users and developers. Akaunting is a free, open source and online accounting software designed for small businesses and freelancers. It is built with modern technologies such as Laravel, VueJS, Tailwind, RESTful API etc. Thanks to its modular structure, Akaunting provides an awesome App Store for users and developers.
* [Home](https://akaunting.com) - The house of Akaunting * [Home](https://akaunting.com) - The house of Akaunting
* [Forum](https://akaunting.com/forum) - Ask for support * [Forum](https://akaunting.com/forum) - Ask for support
* [Documentation](https://akaunting.com/docs) - Learn how to use * [Documentation](https://akaunting.com/hc/docs) - Learn how to use
* [Developer Portal](https://developer.akaunting.com) - Generate passive income * [Developer Portal](https://developer.akaunting.com) - Generate passive income
* [App Store](https://akaunting.com/apps) - Extend your Akaunting * [App Store](https://akaunting.com/apps) - Extend your Akaunting
* [Translations](https://crowdin.com/project/akaunting) - Help us translate Akaunting * [Translations](https://crowdin.com/project/akaunting) - Help us translate Akaunting
## Requirements ## Requirements
* PHP 8.0 or higher * PHP 8.1 or higher
* Database (eg: MySQL, PostgreSQL, SQLite) * Database (eg: MySQL, PostgreSQL, SQLite)
* Web Server (eg: Apache, Nginx, IIS) * Web Server (eg: Apache, Nginx, IIS)
* [Other libraries](https://akaunting.com/docs/requirements) * [Other libraries](https://akaunting.com/hc/docs/on-premise/requirements/)
## Framework ## Framework

View File

@ -15,9 +15,10 @@ use Maatwebsite\Excel\Concerns\ShouldAutoSize;
use Maatwebsite\Excel\Concerns\WithHeadings; use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithMapping; use Maatwebsite\Excel\Concerns\WithMapping;
use Maatwebsite\Excel\Concerns\WithTitle; use Maatwebsite\Excel\Concerns\WithTitle;
use Maatwebsite\Excel\Concerns\WithStrictNullComparison;
use PhpOffice\PhpSpreadsheet\Shared\Date as ExcelDate; use PhpOffice\PhpSpreadsheet\Shared\Date as ExcelDate;
abstract class Export implements FromCollection, HasLocalePreference, ShouldAutoSize, ShouldQueue, WithHeadings, WithMapping, WithTitle abstract class Export implements FromCollection, HasLocalePreference, ShouldAutoSize, ShouldQueue, WithHeadings, WithMapping, WithTitle, WithStrictNullComparison
{ {
use Exportable; use Exportable;
@ -48,13 +49,18 @@ abstract class Export implements FromCollection, HasLocalePreference, ShouldAuto
{ {
$map = []; $map = [];
$date_fields = ['paid_at', 'invoiced_at', 'billed_at', 'due_at', 'issued_at', 'created_at', 'transferred_at']; $date_fields = ['paid_at', 'invoiced_at', 'billed_at', 'due_at', 'issued_at', 'transferred_at'];
$evil_chars = ['=', '+', '-', '@']; $evil_chars = ['=', '+', '-', '@'];
foreach ($this->fields as $field) { foreach ($this->fields as $field) {
$value = $model->$field; $value = $model->$field;
// created_by is equal to the owner id. Therefore, the value in export is owner email.
if ($field == 'created_by') {
$value = $model->owner->email ?? null;
}
if (in_array($field, $date_fields)) { if (in_array($field, $date_fields)) {
$value = ExcelDate::PHPToExcel(Date::parse($value)->format('Y-m-d')); $value = ExcelDate::PHPToExcel(Date::parse($value)->format('Y-m-d'));
} }

View File

@ -2,6 +2,7 @@
namespace App\Abstracts; namespace App\Abstracts;
use App\Abstracts\Http\FormRequest;
use App\Traits\Import as ImportHelper; use App\Traits\Import as ImportHelper;
use App\Traits\Sources; use App\Traits\Sources;
use App\Utilities\Date; use App\Utilities\Date;
@ -11,6 +12,7 @@ use Illuminate\Contracts\Translation\HasLocalePreference;
use Illuminate\Support\Arr; use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator; use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;
use Maatwebsite\Excel\Concerns\Importable; use Maatwebsite\Excel\Concerns\Importable;
use Maatwebsite\Excel\Concerns\SkipsEmptyRows; use Maatwebsite\Excel\Concerns\SkipsEmptyRows;
use Maatwebsite\Excel\Concerns\ToModel; use Maatwebsite\Excel\Concerns\ToModel;
@ -27,6 +29,8 @@ abstract class Import implements HasLocalePreference, ShouldQueue, SkipsEmptyRow
public $user; public $user;
public $request_class = null;
public function __construct() public function __construct()
{ {
$this->user = user(); $this->user = user();
@ -35,7 +39,12 @@ abstract class Import implements HasLocalePreference, ShouldQueue, SkipsEmptyRow
public function map($row): array public function map($row): array
{ {
$row['company_id'] = company_id(); $row['company_id'] = company_id();
$row['created_by'] = $this->user->id;
// created_by is equal to the owner id. Therefore, the value in export is owner email.
if (isset($row['created_by'])) {
$row['created_by'] = $this->getCreatedById($row);
}
$row['created_from'] = $this->getSourcePrefix() . 'import'; $row['created_from'] = $this->getSourcePrefix() . 'import';
// Make enabled field integer // Make enabled field integer
@ -48,7 +57,7 @@ abstract class Import implements HasLocalePreference, ShouldQueue, SkipsEmptyRow
$row['reconciled'] = (int) $row['reconciled']; $row['reconciled'] = (int) $row['reconciled'];
} }
$date_fields = ['paid_at', 'invoiced_at', 'billed_at', 'due_at', 'issued_at', 'created_at', 'transferred_at']; $date_fields = ['paid_at', 'invoiced_at', 'billed_at', 'due_at', 'issued_at', 'transferred_at'];
foreach ($date_fields as $date_field) { foreach ($date_fields as $date_field) {
if (!isset($row[$date_field])) { if (!isset($row[$date_field])) {
continue; continue;
@ -70,6 +79,49 @@ abstract class Import implements HasLocalePreference, ShouldQueue, SkipsEmptyRow
return []; return [];
} }
/**
* You can override this method to add custom rules for each row.
*/
public function prepareRules(array $rules): array
{
return $rules;
}
/**
* Validate each row data.
*
* @param \Illuminate\Validation\Validator $validator
* @throws ValidationException
*/
public function withValidator($validator)
{
$condition = class_exists($this->request_class)
? ! ($request = new $this->request_class) instanceof FormRequest
: true;
if ($condition) {
return;
}
foreach ($validator->getData() as $row => $data) {
$request->initialize(request: $data);
$rules = $this->prepareRules($request->rules());
try {
Validator::make($data, $rules)->validate();
} catch (ValidationException $e) {
foreach ($e->validator->failed() as $attribute => $value) {
foreach ($value as $rule => $params) {
$validator->addFailure($row . '.' . $attribute, $rule, $params);
}
}
throw new ValidationException($validator);
}
}
}
public function chunkSize(): int public function chunkSize(): int
{ {
return config('excel.imports.chunk_size'); return config('excel.imports.chunk_size');

View File

@ -20,6 +20,6 @@ abstract class ImportMultipleSheets implements ShouldQueue, WithChunkReading, Wi
public function chunkSize(): int public function chunkSize(): int
{ {
return 100; return config('excel.imports.chunk_size');
} }
} }

View File

@ -22,10 +22,10 @@ abstract class Model extends Eloquent implements Ownable
protected $tenantable = true; protected $tenantable = true;
protected $dates = ['deleted_at'];
protected $casts = [ protected $casts = [
'enabled' => 'boolean', 'amount' => 'double',
'enabled' => 'boolean',
'deleted_at' => 'datetime',
]; ];
public $allAttributes = []; public $allAttributes = [];
@ -105,7 +105,7 @@ abstract class Model extends Eloquent implements Ownable
/** /**
* Modules that use the sort parameter in CRUD operations cause an error, * Modules that use the sort parameter in CRUD operations cause an error,
* so this sort parameter set back to old value after the query is executed. * so this sort parameter set back to old value after the query is executed.
* *
* for Custom Fields module * for Custom Fields module
*/ */
$request_sort = $request->get('sort'); $request_sort = $request->get('sort');
@ -117,7 +117,8 @@ abstract class Model extends Eloquent implements Ownable
} }
$request->merge(['sort' => $request_sort]); $request->merge(['sort' => $request_sort]);
$request->offsetUnset('direction'); // This line disabled because broken sortable issue.
//$request->offsetUnset('direction');
$limit = (int) $request->get('limit', setting('default.list_limit', '25')); $limit = (int) $request->get('limit', setting('default.list_limit', '25'));
return $query->paginate($limit); return $query->paginate($limit);

View File

@ -222,7 +222,9 @@ abstract class Report
foreach ($tmp_values as $id => $value) { foreach ($tmp_values as $id => $value) {
$labels[$id] = $this->row_names[$table_key][$id]; $labels[$id] = $this->row_names[$table_key][$id];
$colors[$id] = ($group == 'category') ? Category::withSubCategory()->find($id)?->colorHexCode : '#' . dechex(rand(0x000000, 0xFFFFFF)); $colors[$id] = ($group == 'category')
? Category::withSubCategory()->find($id)?->colorHexCode
: $this->randHexColor();
$values[$id] = round(($value * 100 / $total), 0); $values[$id] = round(($value * 100 / $total), 0);
} }
@ -642,4 +644,14 @@ abstract class Report
], ],
]; ];
} }
public function randHexColorPart(): string
{
return str_pad( dechex( mt_rand( 0, 255 ) ), 2, '0', STR_PAD_LEFT);
}
public function randHexColor(): string
{
return '#' . $this->randHexColorPart() . $this->randHexColorPart() . $this->randHexColorPart();
}
} }

View File

@ -283,8 +283,8 @@ abstract class Index extends Component
$items[] = [ $items[] = [
'title' => ($key == 'overdue') ? trans('general.overdue') : trans('documents.statuses.' . $key), 'title' => ($key == 'overdue') ? trans('general.overdue') : trans('documents.statuses.' . $key),
//'href' => route($route, ['search' => 'status:' . $key]), //'href' => route($route, ['search' => 'status:' . $key]),
'amount' => money($total, default_currency(), true)->formatForHumans(), 'amount' => money($total)->formatForHumans(),
'tooltip' => money($total, default_currency(), true)->format(), 'tooltip' => money($total)->format(),
]; ];
} }

View File

@ -3,6 +3,7 @@
namespace App\Abstracts\View\Components\Documents; namespace App\Abstracts\View\Components\Documents;
use App\Abstracts\View\Component; use App\Abstracts\View\Component;
use App\Interfaces\Utility\DocumentNumber;
use App\Models\Common\Contact; use App\Models\Common\Contact;
use App\Models\Document\Document; use App\Models\Document\Document;
use App\Models\Setting\Currency; use App\Models\Setting\Currency;
@ -163,30 +164,45 @@ abstract class Form extends Component
/** @var bool */ /** @var bool */
public $hideItemName; public $hideItemName;
/** @var bool */
public $hideSettingItemName;
/** @var string */ /** @var string */
public $textItemName; public $textItemName;
/** @var bool */ /** @var bool */
public $hideItemDescription; public $hideItemDescription;
/** @var bool */
public $hideSettingItemDescription;
/** @var string */ /** @var string */
public $textItemDescription; public $textItemDescription;
/** @var bool */ /** @var bool */
public $hideItemQuantity; public $hideItemQuantity;
/** @var bool */
public $hideSettingItemQuantity;
/** @var string */ /** @var string */
public $textItemQuantity; public $textItemQuantity;
/** @var bool */ /** @var bool */
public $hideItemPrice; public $hideItemPrice;
/** @var bool */
public $hideSettingItemPrice;
/** @var string */ /** @var string */
public $textItemPrice; public $textItemPrice;
/** @var bool */ /** @var bool */
public $hideItemAmount; public $hideItemAmount;
/** @var bool */
public $hideSettingItemAmount;
/** @var string */ /** @var string */
public $textItemAmount; public $textItemAmount;
@ -276,8 +292,8 @@ abstract class Form extends Component
bool $hideDocumentTitle = false, bool $hideDocumentSubheading = false, string $title = '', string $subheading = '', bool $hideDocumentTitle = false, bool $hideDocumentSubheading = false, string $title = '', string $subheading = '',
bool $hideIssuedAt = false, string $textIssuedAt = '', string $issuedAt = '', bool $hideDueAt = false, string $textDueAt = '', string $dueAt = '', $periodDueAt = '', bool $hideIssuedAt = false, string $textIssuedAt = '', string $issuedAt = '', bool $hideDueAt = false, string $textDueAt = '', string $dueAt = '', $periodDueAt = '',
bool $hideDocumentNumber = false, string $textDocumentNumber = '', string $documentNumber = '', bool $hideOrderNumber = false, string $textOrderNumber = '', string $orderNumber = '', bool $hideDocumentNumber = false, string $textDocumentNumber = '', string $documentNumber = '', bool $hideOrderNumber = false, string $textOrderNumber = '', string $orderNumber = '',
bool $hideEditItemColumns = false, bool $hideItems = false, bool $hideItemName = false, string $textItemName = '', bool $hideItemDescription = false, string $textItemDescription = '', bool $hideEditItemColumns = false, bool $hideItems = false, bool $hideItemName = false, bool $hideSettingItemName = false, string $textItemName = '', bool $hideItemDescription = false, bool $hideSettingItemDescription = false, string $textItemDescription = '',
bool $hideItemQuantity = false, string $textItemQuantity = '', bool $hideItemPrice = false, string $textItemPrice = '', bool $hideItemAmount = false, string $textItemAmount = '', bool $hideItemQuantity = false, bool $hideSettingItemQuantity = false, string $textItemQuantity = '', bool $hideItemPrice = false, bool $hideSettingItemPrice = false, string $textItemPrice = '', bool $hideItemAmount = false, bool $hideSettingItemAmount = false, string $textItemAmount = '',
bool $hideDiscount = false, bool $isSalePrice = false, bool $isPurchasePrice = false, int $searchCharLimit = 0, string $notes = '', bool $hideDiscount = false, bool $isSalePrice = false, bool $isPurchasePrice = false, int $searchCharLimit = 0, string $notes = '',
bool $showRecurring = false, bool $showRecurring = false,
bool $hideAdvanced = false, string $textSectionAdvancedTitle = '', string $textSectionAdvancedDescription = '', bool $hideAdvanced = false, string $textSectionAdvancedTitle = '', string $textSectionAdvancedDescription = '',
@ -290,9 +306,11 @@ abstract class Form extends Component
$this->model = ! empty($model) ? $model : $document; $this->model = ! empty($model) ? $model : $document;
$this->document = $this->model; $this->document = $this->model;
$this->currencies = $this->getCurrencies($currencies);
$this->currency = $this->getCurrency($document, $currency, $currency_code);
$this->currency_code = ! empty($this->currency) ? $this->currency->code : default_currency(); $this->currency_code = ! empty($this->currency) ? $this->currency->code : default_currency();
$this->currency = $this->getCurrency($document, $currency, $currency_code);
$this->currencies = $this->getCurrencies($currencies);
$this->taxes = Tax::enabled()->orderBy('name')->get()->pluck('title', 'id'); $this->taxes = Tax::enabled()->orderBy('name')->get()->pluck('title', 'id');
/* -- Content Start -- */ /* -- Content Start -- */
@ -357,18 +375,23 @@ abstract class Form extends Component
$this->hideItems = $this->getHideItems($type, $hideItems, $hideItemName, $hideItemDescription); $this->hideItems = $this->getHideItems($type, $hideItems, $hideItemName, $hideItemDescription);
$this->hideItemName = $this->getHideItemName($type, $hideItemName); $this->hideItemName = $this->getHideItemName($type, $hideItemName);
$this->hideSettingItemName = $this->getHideSettingItemName($type, $hideSettingItemName);
$this->textItemName = $this->getTextItemName($type, $textItemName); $this->textItemName = $this->getTextItemName($type, $textItemName);
$this->hideItemDescription = $this->getHideItemDescription($type, $hideItemDescription); $this->hideItemDescription = $this->getHideItemDescription($type, $hideItemDescription);
$this->hideSettingItemDescription = $this->getHideSettingItemDescription($type, $hideSettingItemDescription);
$this->textItemDescription = $this->getTextItemDescription($type, $textItemDescription); $this->textItemDescription = $this->getTextItemDescription($type, $textItemDescription);
$this->hideItemQuantity = $this->getHideItemQuantity($type, $hideItemQuantity); $this->hideItemQuantity = $this->getHideItemQuantity($type, $hideItemQuantity);
$this->hideSettingItemQuantity = $this->getHideSettingItemQuantity($type, $hideSettingItemQuantity);
$this->textItemQuantity = $this->getTextItemQuantity($type, $textItemQuantity); $this->textItemQuantity = $this->getTextItemQuantity($type, $textItemQuantity);
$this->hideItemPrice = $this->getHideItemPrice($type, $hideItemPrice); $this->hideItemPrice = $this->getHideItemPrice($type, $hideItemPrice);
$this->hideSettingItemPrice = $this->getHideSettingItemPrice($type, $hideSettingItemPrice);
$this->textItemPrice = $this->getTextItemPrice($type, $textItemPrice); $this->textItemPrice = $this->getTextItemPrice($type, $textItemPrice);
$this->hideItemAmount = $this->getHideItemAmount($type, $hideItemAmount); $this->hideItemAmount = $this->getHideItemAmount($type, $hideItemAmount);
$this->hideSettingItemAmount = $this->getHideSettingItemAmount($type, $hideSettingItemAmount);
$this->textItemAmount = $this->getTextItemAmount($type, $textItemAmount); $this->textItemAmount = $this->getTextItemAmount($type, $textItemAmount);
$this->hideDiscount = $this->getHideDiscount($type, $hideDiscount); $this->hideDiscount = $this->getHideDiscount($type, $hideDiscount);
@ -763,7 +786,7 @@ abstract class Form extends Component
$issuedAt = Date::now()->toDateString(); $issuedAt = Date::now()->toDateString();
} }
$addDays = setting($this->getSettingKey($type, 'payment_terms'), 0) ?: 0; $addDays = setting($this->getDocumentSettingKey($type, 'payment_terms'), 0) ?: 0;
$dueAt = Date::parse($issuedAt)->addDays($addDays)->toDateString(); $dueAt = Date::parse($issuedAt)->addDays($addDays)->toDateString();
@ -815,10 +838,14 @@ abstract class Form extends Component
return $document->document_number; return $document->document_number;
} }
$document_number = $this->getNextDocumentNumber($type); $contact = ($this->contact instanceof Contact) ? $this->contact : null;
$utility = app(DocumentNumber::class);
$document_number = $utility->getNextNumber($type, $contact);
if (empty($document_number)) { if (empty($document_number)) {
$document_number = $this->getNextDocumentNumber(Document::INVOICE_TYPE); $document_number = $utility->getNextNumber(Document::INVOICE_TYPE, $contact);
} }
return $document_number; return $document_number;
@ -869,25 +896,35 @@ abstract class Form extends Component
return $hideItems; return $hideItems;
} }
protected function getHideItemName($type, $hideItemName) protected function getHideItemName($type, $hideItemName): bool
{ {
if (! empty($hideItemName)) { if (! empty($hideItemName)) {
return $hideItemName; return $hideItemName;
} }
// if you use settting translation
if ($hideItemName = setting($this->getSettingKey($type, 'item_name'), false) && $hideItemName == 'hide') {
return $hideItemName;
}
$hide = $this->getHideFromConfig($type, 'name'); $hide = $this->getHideFromConfig($type, 'name');
if ($hide) { if ($hide) {
return $hide; return $hide;
} }
// @todo what return value invoice or always false?? return false;
return setting('invoice.item_name', $hideItemName) == 'hide' ? true : false; }
protected function getHideSettingItemName($type, $hideSettingItemName): bool
{
if (! empty($hideSettingItemName)) {
return $hideSettingItemName;
}
$hideItemName = setting($this->getDocumentSettingKey($type, 'item_name'), false);
// if you use settting translation
if ($hideItemName === 'hide') {
return true;
}
return false;
} }
protected function getTextItemName($type, $textItemName) protected function getTextItemName($type, $textItemName)
@ -897,18 +934,18 @@ abstract class Form extends Component
} }
// if you use settting translation // if you use settting translation
if (setting($this->getSettingKey($type, 'item_name'), 'items') === 'custom') { if (setting($this->getDocumentSettingKey($type, 'item_name'), 'items') === 'custom') {
if (empty($textItemName = setting($this->getSettingKey($type, 'item_name_input')))) { if (empty($textItemName = setting($this->getDocumentSettingKey($type, 'item_name_input')))) {
$textItemName = 'general.items'; $textItemName = 'general.items';
} }
return $textItemName; return $textItemName;
} }
if (setting($this->getSettingKey($type, 'item_name')) !== null if (setting($this->getDocumentSettingKey($type, 'item_name')) !== null
&& (trans(setting($this->getSettingKey($type, 'item_name'))) != setting($this->getSettingKey($type, 'item_name'))) && (trans(setting($this->getDocumentSettingKey($type, 'item_name'))) != setting($this->getDocumentSettingKey($type, 'item_name')))
) { ) {
return setting($this->getSettingKey($type, 'item_name')); return setting($this->getDocumentSettingKey($type, 'item_name'));
} }
$translation = $this->getTextFromConfig($type, 'items'); $translation = $this->getTextFromConfig($type, 'items');
@ -920,25 +957,33 @@ abstract class Form extends Component
return 'general.items'; return 'general.items';
} }
protected function getHideItemDescription($type, $hideItemDescription) protected function getHideItemDescription($type, $hideItemDescription): bool
{ {
if (! empty($hideItemDescription)) { if (! empty($hideItemDescription)) {
return $hideItemDescription; return $hideItemDescription;
} }
// if you use settting translation
if ($hideItemDescription = setting($this->getSettingKey($type, 'hide_item_description'), false) && $hideItemDescription == 'hide') {
return $hideItemDescription;
}
$hide = $this->getHideFromConfig($type, 'description'); $hide = $this->getHideFromConfig($type, 'description');
if ($hide) { if ($hide) {
return $hide; return $hide;
} }
// @todo what return value invoice or always false?? return false;
return setting('invoice.hide_item_description', $hideItemDescription); }
protected function getHideSettingItemDescription($type, $hideSettingItemDescription): bool
{
if (! empty($hideSettingItemDescription)) {
return $hideSettingItemDescription;
}
// if you use settting translation
if (setting($this->getDocumentSettingKey($type, 'hide_item_description'), false)) {
return true;
}
return false;
} }
protected function getTextItemDescription($type, $textItemDescription) protected function getTextItemDescription($type, $textItemDescription)
@ -956,25 +1001,35 @@ abstract class Form extends Component
return 'general.description'; return 'general.description';
} }
protected function getHideItemQuantity($type, $hideItemQuantity) protected function getHideItemQuantity($type, $hideItemQuantity): bool
{ {
if (! empty($hideItemQuantity)) { if (! empty($hideItemQuantity)) {
return $hideItemQuantity; return $hideItemQuantity;
} }
// if you use settting translation
if ($hideItemQuantity = setting($this->getSettingKey($type, 'hide_quantity'), false) && $hideItemQuantity == 'hide') {
return $hideItemQuantity;
}
$hide = $this->getHideFromConfig($type, 'quantity'); $hide = $this->getHideFromConfig($type, 'quantity');
if ($hide) { if ($hide) {
return $hide; return $hide;
} }
// @todo what return value invoice or always false?? return false;
return setting('invoice.quantity_name', $hideItemQuantity) == 'hide' ? true : false; }
protected function getHideSettingItemQuantity($type, $hideSettingItemQuantity): bool
{
if (! empty($hideSettingItemQuantity)) {
return $hideSettingItemQuantity;
}
$hideItemQuantity = setting($this->getDocumentSettingKey($type, 'quantity_name'), false);
// if you use settting translation
if ($hideItemQuantity === 'hide') {
return true;
}
return false;
} }
protected function getTextItemQuantity($type, $textItemQuantity) protected function getTextItemQuantity($type, $textItemQuantity)
@ -984,18 +1039,18 @@ abstract class Form extends Component
} }
// if you use settting translation // if you use settting translation
if (setting($this->getSettingKey($type, 'quantity_name'), 'quantity') === 'custom') { if (setting($this->getDocumentSettingKey($type, 'quantity_name'), 'quantity') === 'custom') {
if (empty($textItemQuantity = setting($this->getSettingKey($type, 'quantity_name_input')))) { if (empty($textItemQuantity = setting($this->getDocumentSettingKey($type, 'quantity_name_input')))) {
$textItemQuantity = 'invoices.quantity'; $textItemQuantity = 'invoices.quantity';
} }
return $textItemQuantity; return $textItemQuantity;
} }
if (setting($this->getSettingKey($type, 'quantity_name')) !== null if (setting($this->getDocumentSettingKey($type, 'quantity_name')) !== null
&& (trans(setting($this->getSettingKey($type, 'quantity_name'))) != setting($this->getSettingKey($type, 'quantity_name'))) && (trans(setting($this->getDocumentSettingKey($type, 'quantity_name'))) != setting($this->getDocumentSettingKey($type, 'quantity_name')))
) { ) {
return setting($this->getSettingKey($type, 'quantity_name')); return setting($this->getDocumentSettingKey($type, 'quantity_name'));
} }
$translation = $this->getTextFromConfig($type, 'quantity'); $translation = $this->getTextFromConfig($type, 'quantity');
@ -1007,25 +1062,35 @@ abstract class Form extends Component
return 'invoices.quantity'; return 'invoices.quantity';
} }
protected function getHideItemPrice($type, $hideItemPrice) protected function getHideItemPrice($type, $hideItemPrice): bool
{ {
if (! empty($hideItemPrice)) { if (! empty($hideItemPrice)) {
return $hideItemPrice; return $hideItemPrice;
} }
// if you use settting translation
if ($hideItemPrice = setting($this->getSettingKey($type, 'hide_price'), false) && $hideItemPrice == 'hide') {
return $hideItemPrice;
}
$hide = $this->getHideFromConfig($type, 'price'); $hide = $this->getHideFromConfig($type, 'price');
if ($hide) { if ($hide) {
return $hide; return $hide;
} }
// @todo what return value invoice or always false?? return false;
return setting('invoice.price_name', $hideItemPrice) == 'hide' ? true : false; }
protected function getHideSettingItemPrice($type, $hideSettingItemPrice): bool
{
if (! empty($hideSettingItemPrice)) {
return $hideSettingItemPrice;
}
$hideItemPrice = setting($this->getDocumentSettingKey($type, 'price_name'), false);
// if you use settting translation
if ($hideItemPrice === 'hide') {
return true;
}
return false;
} }
protected function getTextItemPrice($type, $textItemPrice) protected function getTextItemPrice($type, $textItemPrice)
@ -1035,18 +1100,18 @@ abstract class Form extends Component
} }
// if you use settting translation // if you use settting translation
if (setting($this->getSettingKey($type, 'price_name'), 'price') === 'custom') { if (setting($this->getDocumentSettingKey($type, 'price_name'), 'price') === 'custom') {
if (empty($textItemPrice = setting($this->getSettingKey($type, 'price_name_input')))) { if (empty($textItemPrice = setting($this->getDocumentSettingKey($type, 'price_name_input')))) {
$textItemPrice = 'invoices.price'; $textItemPrice = 'invoices.price';
} }
return $textItemPrice; return $textItemPrice;
} }
if (setting($this->getSettingKey($type, 'price_name')) !== null if (setting($this->getDocumentSettingKey($type, 'price_name')) !== null
&& (trans(setting($this->getSettingKey($type, 'price_name'))) != setting($this->getSettingKey($type, 'price_name'))) && (trans(setting($this->getDocumentSettingKey($type, 'price_name'))) != setting($this->getDocumentSettingKey($type, 'price_name')))
) { ) {
return setting($this->getSettingKey($type, 'price_name')); return setting($this->getDocumentSettingKey($type, 'price_name'));
} }
$translation = $this->getTextFromConfig($type, 'price'); $translation = $this->getTextFromConfig($type, 'price');
@ -1058,25 +1123,33 @@ abstract class Form extends Component
return 'invoices.price'; return 'invoices.price';
} }
protected function getHideItemAmount($type, $hideItemAmount) protected function getHideItemAmount($type, $hideItemAmount): bool
{ {
if (! empty($hideItemAmount)) { if (! empty($hideItemAmount)) {
return $hideItemAmount; return $hideItemAmount;
} }
// if you use settting translation
if ($hideAmount = setting($this->getSettingKey($type, 'hide_amount'), false)) {
return $hideAmount;
}
$hide = $this->getHideFromConfig($type, 'amount'); $hide = $this->getHideFromConfig($type, 'amount');
if ($hide) { if ($hide) {
return $hide; return $hide;
} }
// @todo what return value invoice or always false?? return false;
return setting('invoice.hide_amount', $hideAmount); }
protected function getHideSettingItemAmount($type, $hideSettingItemAmount): bool
{
if (! empty($hideSettingItemAmount)) {
return $hideSettingItemAmount;
}
// if you use settting translation
if (setting($this->getDocumentSettingKey($type, 'hide_amount'), false)) {
return true;
}
return false;
} }
protected function getTextItemAmount($type, $textItemAmount) protected function getTextItemAmount($type, $textItemAmount)
@ -1101,7 +1174,7 @@ abstract class Form extends Component
} }
// if you use settting translation // if you use settting translation
if ($hideDiscount = setting($this->getSettingKey($type, 'hide_discount'), false)) { if ($hideDiscount = setting($this->getDocumentSettingKey($type, 'hide_discount'), false)) {
return $hideDiscount; return $hideDiscount;
} }
@ -1122,7 +1195,7 @@ abstract class Form extends Component
} }
// if you use settting translation // if you use settting translation
if ($settingCharLimit = setting($this->getSettingKey($type, 'item_search_chart_limit'), false)) { if ($settingCharLimit = setting($this->getDocumentSettingKey($type, 'item_search_chart_limit'), false)) {
return $settingCharLimit; return $settingCharLimit;
} }
@ -1146,7 +1219,7 @@ abstract class Form extends Component
return $this->document->notes; return $this->document->notes;
} }
return setting($this->getSettingKey($this->type, 'notes')); return setting($this->getDocumentSettingKey($this->type, 'notes'));
} }
protected function getTextSectionAdvancedTitle($type, $textSectionAdvancedTitle) protected function getTextSectionAdvancedTitle($type, $textSectionAdvancedTitle)
@ -1177,7 +1250,7 @@ abstract class Form extends Component
return $this->document->title; return $this->document->title;
} }
return setting($this->getSettingKey($type, 'title')); return setting($this->getDocumentSettingKey($type, 'title'));
} }
protected function getSubheadingValue($type, $subheading) protected function getSubheadingValue($type, $subheading)
@ -1190,7 +1263,7 @@ abstract class Form extends Component
return $this->document->subheading; return $this->document->subheading;
} }
return setting($this->getSettingKey($type, 'subheading')); return setting($this->getDocumentSettingKey($type, 'subheading'));
} }
protected function getFooterValue($footer) protected function getFooterValue($footer)
@ -1203,7 +1276,7 @@ abstract class Form extends Component
return $this->document->footer; return $this->document->footer;
} }
return setting($this->getSettingKey($this->type, 'footer')); return setting($this->getDocumentSettingKey($this->type, 'footer'));
} }
protected function getTypeCategory($type, $typeCategory) protected function getTypeCategory($type, $typeCategory)

View File

@ -392,8 +392,8 @@ abstract class Index extends Component
foreach ($totals as $key => $total) { foreach ($totals as $key => $total) {
$title = ($key == 'overdue') ? trans('general.overdue') : trans('documents.statuses.' . $key); $title = ($key == 'overdue') ? trans('general.overdue') : trans('documents.statuses.' . $key);
$href = route($route, ['search' => 'status:' . $key]); $href = route($route, ['search' => 'status:' . $key]);
$amount = money($total, default_currency(), true)->formatForHumans(); $amount = money($total)->formatForHumans();
$tooltip = money($total, default_currency(), true)->format(); $tooltip = money($total)->format();
$items[] = [ $items[] = [
'title' => $title, 'title' => $title,

View File

@ -11,7 +11,6 @@ use App\Abstracts\View\Component;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\URL; use Illuminate\Support\Facades\URL;
use Illuminate\Support\Facades\File; use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use Intervention\Image\Exception\NotReadableException; use Intervention\Image\Exception\NotReadableException;
use Image; use Image;
@ -742,9 +741,7 @@ abstract class Show extends Component
return $textRecurringType; return $textRecurringType;
} }
$default_key = config('type.' . static::OBJECT_TYPE . '.' . $type . '.translation.prefix'); $translation = config('type.' . static::OBJECT_TYPE . '.' . $type . '.translation.tab_document');
$translation = $this->getTextFromConfig($type, 'recurring_tye', $default_key);
if (! empty($translation)) { if (! empty($translation)) {
return $translation; return $translation;
@ -910,7 +907,7 @@ abstract class Show extends Component
return $template; return $template;
} }
$documentTemplate = setting($this->getSettingKey($type, 'template'), 'default'); $documentTemplate = setting($this->getDocumentSettingKey($type, 'template'), 'default');
return $documentTemplate; return $documentTemplate;
} }
@ -928,7 +925,7 @@ abstract class Show extends Component
if (! empty($media)) { if (! empty($media)) {
$path = $media->getDiskPath(); $path = $media->getDiskPath();
if (Storage::missing($path)) { if (! $media->fileExists()) {
return $logo; return $logo;
} }
} else { } else {
@ -941,7 +938,7 @@ abstract class Show extends Component
$height = setting('invoice.logo_size_height'); $height = setting('invoice.logo_size_height');
if ($media) { if ($media) {
$image->make(Storage::get($path))->resize($width, $height)->encode(); $image->make($media->contents())->resize($width, $height)->encode();
} else { } else {
$image->make($path)->resize($width, $height)->encode(); $image->make($path)->resize($width, $height)->encode();
} }
@ -975,21 +972,28 @@ abstract class Show extends Component
return $backgroundColor; return $backgroundColor;
} }
if ($background_color = config('type.' . static::OBJECT_TYPE . '.' . $type . '.color', false)) { // checking setting color
return $background_color; $key = $this->getDocumentSettingKey($type, 'color');
if (! empty(setting($key))) {
$backgroundColor = setting($key);
} }
if (! empty($alias = config('type.' . static::OBJECT_TYPE . '.' . $type . '.alias'))) { // checking config color
$type = $alias . '.' . str_replace('-', '_', $type); if (empty($backgroundColor) && $background_color = config('type.document.' . $type . '.color', false)) {
$backgroundColor = $background_color;
} }
$backgroundColor = setting($this->getSettingKey($type, 'color'), '#55588b'); // set default color
if (empty($backgroundColor)) {
$backgroundColor = '#55588b';
}
return $this->getHexCodeOfTailwindClass($backgroundColor); return $this->getHexCodeOfTailwindClass($backgroundColor);
} }
protected function getTextDocumentTitle($type, $textDocumentTitle) protected function getTextDocumentTitle($type, $textDocumentTitle)
{ {
if (! empty($textDocumentTitle)) { if (! empty($textDocumentTitle)) {
return $textDocumentTitle; return $textDocumentTitle;
} }
@ -998,7 +1002,7 @@ abstract class Show extends Component
return $this->document->title; return $this->document->title;
} }
$key = $this->getSettingKey($type, 'title'); $key = $this->getDocumentSettingKey($type, 'title');
if (! empty(setting($key))) { if (! empty(setting($key))) {
return setting($key); return setting($key);
@ -1023,7 +1027,7 @@ abstract class Show extends Component
return $this->document->subheading; return $this->document->subheading;
} }
$key = $this->getSettingKey($type, 'subheading'); $key = $this->getDocumentSettingKey($type, 'subheading');
if (!empty(setting($key))) { if (!empty(setting($key))) {
return setting($key); return setting($key);
@ -1153,8 +1157,8 @@ abstract class Show extends Component
} }
// if you use settting translation // if you use settting translation
if (setting($this->getSettingKey($type, 'item_name'), 'items') == 'custom') { if (setting($this->getDocumentSettingKey($type, 'item_name'), 'items') == 'custom') {
if (empty($textItems = setting($this->getSettingKey($type, 'item_name_input')))) { if (empty($textItems = setting($this->getDocumentSettingKey($type, 'item_name_input')))) {
$textItems = 'general.items'; $textItems = 'general.items';
} }
@ -1177,8 +1181,8 @@ abstract class Show extends Component
} }
// if you use settting translation // if you use settting translation
if (setting($this->getSettingKey($type, 'quantity_name'), 'quantity') === 'custom') { if (setting($this->getDocumentSettingKey($type, 'quantity_name'), 'quantity') === 'custom') {
if (empty($textQuantity = setting($this->getSettingKey($type, 'quantity_name_input')))) { if (empty($textQuantity = setting($this->getDocumentSettingKey($type, 'quantity_name_input')))) {
$textQuantity = 'invoices.quantity'; $textQuantity = 'invoices.quantity';
} }
@ -1201,8 +1205,8 @@ abstract class Show extends Component
} }
// if you use settting translation // if you use settting translation
if (setting($this->getSettingKey($type, 'price_name'), 'price') === 'custom') { if (setting($this->getDocumentSettingKey($type, 'price_name'), 'price') === 'custom') {
if (empty($textPrice = setting($this->getSettingKey($type, 'price_name_input')))) { if (empty($textPrice = setting($this->getDocumentSettingKey($type, 'price_name_input')))) {
$textPrice = 'invoices.price'; $textPrice = 'invoices.price';
} }
@ -1256,9 +1260,11 @@ abstract class Show extends Component
return $hideName; return $hideName;
} }
$hideName = setting($this->getDocumentSettingKey($type, 'item_name'), false);
// if you use settting translation // if you use settting translation
if ($hideName = setting($this->getSettingKey($type, 'item_name'), false) && $hideName == 'hide') { if ($hideName === 'hide') {
return $hideName; return true;
} }
$hide = $this->getHideFromConfig($type, 'name'); $hide = $this->getHideFromConfig($type, 'name');
@ -1267,8 +1273,7 @@ abstract class Show extends Component
return $hide; return $hide;
} }
// @todo what return value invoice or always false?? return false;
return setting('invoice.item_name', $hideName) == 'hide' ? true : false;
} }
protected function getHideDescription($type, $hideDescription) protected function getHideDescription($type, $hideDescription)
@ -1278,8 +1283,8 @@ abstract class Show extends Component
} }
// if you use settting translation // if you use settting translation
if ($hideDescription = setting($this->getSettingKey($type, 'hide_item_description'), false)) { if (setting($this->getDocumentSettingKey($type, 'hide_item_description'), false)) {
return $hideDescription; return true;
} }
$hide = $this->getHideFromConfig($type, 'description'); $hide = $this->getHideFromConfig($type, 'description');
@ -1288,8 +1293,7 @@ abstract class Show extends Component
return $hide; return $hide;
} }
// @todo what return value invoice or always false?? return false;
return setting('invoice.hide_item_description', $hideDescription);
} }
protected function getHideQuantity($type, $hideQuantity) protected function getHideQuantity($type, $hideQuantity)
@ -1298,9 +1302,11 @@ abstract class Show extends Component
return $hideQuantity; return $hideQuantity;
} }
$hideQuantity = setting($this->getDocumentSettingKey($type, 'quantity_name'), false);
// if you use settting translation // if you use settting translation
if ($hideQuantity = setting($this->getSettingKey($type, 'hide_quantity'), false) && $hideQuantity == 'hide') { if ($hideQuantity === 'hide') {
return $hideQuantity; return true;
} }
$hide = $this->getHideFromConfig($type, 'quantity'); $hide = $this->getHideFromConfig($type, 'quantity');
@ -1309,8 +1315,7 @@ abstract class Show extends Component
return $hide; return $hide;
} }
// @todo what return value invoice or always false?? return false;
return setting('invoice.quantity_name', $hideQuantity) == 'hide' ? true : false;
} }
protected function getHidePrice($type, $hidePrice) protected function getHidePrice($type, $hidePrice)
@ -1319,9 +1324,11 @@ abstract class Show extends Component
return $hidePrice; return $hidePrice;
} }
$hidePrice = setting($this->getDocumentSettingKey($type, 'price_name'), false);
// if you use settting translation // if you use settting translation
if ($hidePrice = setting($this->getSettingKey($type, 'hide_price'), false) && $hidePrice == 'hide') { if ($hidePrice === 'hide') {
return $hidePrice; return true;
} }
$hide = $this->getHideFromConfig($type, 'price'); $hide = $this->getHideFromConfig($type, 'price');
@ -1330,8 +1337,7 @@ abstract class Show extends Component
return $hide; return $hide;
} }
// @todo what return value invoice or always false?? return false;
return setting('invoice.price_name', $hidePrice) == 'hide' ? true : false;
} }
protected function getHideDiscount($type, $hideDiscount) protected function getHideDiscount($type, $hideDiscount)
@ -1341,7 +1347,7 @@ abstract class Show extends Component
} }
// if you use settting translation // if you use settting translation
if ($hideDiscount = setting($this->getSettingKey($type, 'hide_discount'), false)) { if ($hideDiscount = setting($this->getDocumentSettingKey($type, 'hide_discount'), false)) {
return $hideDiscount; return $hideDiscount;
} }
@ -1362,8 +1368,8 @@ abstract class Show extends Component
} }
// if you use settting translation // if you use settting translation
if ($hideAmount = setting($this->getSettingKey($type, 'hide_amount'), false)) { if (setting($this->getDocumentSettingKey($type, 'hide_amount'), false)) {
return $hideAmount; return true;
} }
$hide = $this->getHideFromConfig($type, 'amount'); $hide = $this->getHideFromConfig($type, 'amount');
@ -1372,7 +1378,6 @@ abstract class Show extends Component
return $hide; return $hide;
} }
// @todo what return value invoice or always false?? return false;
return setting('invoice.hide_amount', $hideAmount);
} }
} }

View File

@ -10,7 +10,6 @@ use App\Traits\Tailwind;
use App\Traits\ViewComponents; use App\Traits\ViewComponents;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\File; use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use Intervention\Image\Exception\NotReadableException; use Intervention\Image\Exception\NotReadableException;
use Image; use Image;
@ -210,7 +209,7 @@ abstract class Template extends Component
return $template; return $template;
} }
$documentTemplate = setting($this->getSettingKey($type, 'template'), 'default'); $documentTemplate = setting($this->getDocumentSettingKey($type, 'template'), 'default');
return $documentTemplate; return $documentTemplate;
} }
@ -228,7 +227,7 @@ abstract class Template extends Component
if (! empty($media)) { if (! empty($media)) {
$path = $media->getDiskPath(); $path = $media->getDiskPath();
if (Storage::missing($path)) { if (! $media->fileExists()) {
return $logo; return $logo;
} }
} else { } else {
@ -241,7 +240,7 @@ abstract class Template extends Component
$height = setting('invoice.logo_size_height'); $height = setting('invoice.logo_size_height');
if ($media) { if ($media) {
$image->make(Storage::get($path))->resize($width, $height)->encode(); $image->make($media->contents())->resize($width, $height)->encode();
} else { } else {
$image->make($path)->resize($width, $height)->encode(); $image->make($path)->resize($width, $height)->encode();
} }
@ -275,16 +274,22 @@ abstract class Template extends Component
return $backgroundColor; return $backgroundColor;
} }
if ($background_color = config('type.document.' . $type . '.color', false)) { // checking setting color
return $background_color; $key = $this->getDocumentSettingKey($type, 'color');
if (! empty(setting($key))) {
$backgroundColor = setting($key);
} }
// checking config color
if (! empty($alias = config('type.document.' . $type . '.alias'))) { if (empty($backgroundColor) && $background_color = config('type.document.' . $type . '.color', false)) {
$type = $alias . '.' . str_replace('-', '_', $type); $backgroundColor = $background_color;
} }
$backgroundColor = setting($this->getSettingKey($type, 'color'), '#55588b'); // set default color
if (empty($backgroundColor)) {
$backgroundColor = '#55588b';
}
return $this->getHexCodeOfTailwindClass($backgroundColor); return $this->getHexCodeOfTailwindClass($backgroundColor);
} }
@ -299,7 +304,7 @@ abstract class Template extends Component
return $this->document->title; return $this->document->title;
} }
$key = $this->getSettingKey($type, 'title'); $key = $this->getDocumentSettingKey($type, 'title');
if (! empty(setting($key))) { if (! empty(setting($key))) {
return setting($key); return setting($key);
@ -324,7 +329,7 @@ abstract class Template extends Component
return $this->document->subheading; return $this->document->subheading;
} }
$key = $this->getSettingKey($type, 'subheading'); $key = $this->getDocumentSettingKey($type, 'subheading');
if (! empty(setting($key))) { if (! empty(setting($key))) {
return setting($key); return setting($key);
@ -454,18 +459,18 @@ abstract class Template extends Component
} }
// if you use settting translation // if you use settting translation
if (setting($this->getSettingKey($type, 'item_name'), 'items') === 'custom') { if (setting($this->getDocumentSettingKey($type, 'item_name'), 'items') === 'custom') {
if (empty($textItems = setting($this->getSettingKey($type, 'item_name_input')))) { if (empty($textItems = setting($this->getDocumentSettingKey($type, 'item_name_input')))) {
$textItems = 'general.items'; $textItems = 'general.items';
} }
return $textItems; return $textItems;
} }
if (setting($this->getSettingKey($type, 'item_name')) !== null if (setting($this->getDocumentSettingKey($type, 'item_name')) !== null
&& (trans(setting($this->getSettingKey($type, 'item_name'))) != setting($this->getSettingKey($type, 'item_name'))) && (trans(setting($this->getDocumentSettingKey($type, 'item_name'))) != setting($this->getDocumentSettingKey($type, 'item_name')))
) { ) {
return setting($this->getSettingKey($type, 'item_name')); return setting($this->getDocumentSettingKey($type, 'item_name'));
} }
$translation = $this->getTextFromConfig($type, 'items'); $translation = $this->getTextFromConfig($type, 'items');
@ -484,18 +489,18 @@ abstract class Template extends Component
} }
// if you use settting translation // if you use settting translation
if (setting($this->getSettingKey($type, 'quantity_name'), 'quantity') === 'custom') { if (setting($this->getDocumentSettingKey($type, 'quantity_name'), 'quantity') === 'custom') {
if (empty($textQuantity = setting($this->getSettingKey($type, 'quantity_name_input')))) { if (empty($textQuantity = setting($this->getDocumentSettingKey($type, 'quantity_name_input')))) {
$textQuantity = 'invoices.quantity'; $textQuantity = 'invoices.quantity';
} }
return $textQuantity; return $textQuantity;
} }
if (setting($this->getSettingKey($type, 'quantity_name')) !== null if (setting($this->getDocumentSettingKey($type, 'quantity_name')) !== null
&& (trans(setting($this->getSettingKey($type, 'quantity_name'))) != setting($this->getSettingKey($type, 'quantity_name'))) && (trans(setting($this->getDocumentSettingKey($type, 'quantity_name'))) != setting($this->getDocumentSettingKey($type, 'quantity_name')))
) { ) {
return setting($this->getSettingKey($type, 'quantity_name')); return setting($this->getDocumentSettingKey($type, 'quantity_name'));
} }
$translation = $this->getTextFromConfig($type, 'quantity'); $translation = $this->getTextFromConfig($type, 'quantity');
@ -514,18 +519,18 @@ abstract class Template extends Component
} }
// if you use settting translation // if you use settting translation
if (setting($this->getSettingKey($type, 'price_name'), 'price') === 'custom') { if (setting($this->getDocumentSettingKey($type, 'price_name'), 'price') === 'custom') {
if (empty($textPrice = setting($this->getSettingKey($type, 'price_name_input')))) { if (empty($textPrice = setting($this->getDocumentSettingKey($type, 'price_name_input')))) {
$textPrice = 'invoices.price'; $textPrice = 'invoices.price';
} }
return $textPrice; return $textPrice;
} }
if (setting($this->getSettingKey($type, 'price_name')) !== null if (setting($this->getDocumentSettingKey($type, 'price_name')) !== null
&& (trans(setting($this->getSettingKey($type, 'price_name'))) != setting($this->getSettingKey($type, 'price_name'))) && (trans(setting($this->getDocumentSettingKey($type, 'price_name'))) != setting($this->getDocumentSettingKey($type, 'price_name')))
) { ) {
return setting($this->getSettingKey($type, 'price_name')); return setting($this->getDocumentSettingKey($type, 'price_name'));
} }
$translation = $this->getTextFromConfig($type, 'price'); $translation = $this->getTextFromConfig($type, 'price');
@ -592,9 +597,11 @@ abstract class Template extends Component
return $hideName; return $hideName;
} }
$hideName = setting($this->getDocumentSettingKey($type, 'item_name'), false);
// if you use settting translation // if you use settting translation
if ($hideName = setting($this->getSettingKey($type, 'item_name'), false) && $hideName == 'hide') { if ($hideName === 'hide') {
return $hideName; return true;
} }
$hide = $this->getHideFromConfig($type, 'name'); $hide = $this->getHideFromConfig($type, 'name');
@ -603,8 +610,7 @@ abstract class Template extends Component
return $hide; return $hide;
} }
// @todo what return value invoice or always false?? return false;
return setting('invoice.item_name', $hideName) == 'hide' ? true : false;
} }
protected function getHideDescription($type, $hideDescription) protected function getHideDescription($type, $hideDescription)
@ -614,8 +620,8 @@ abstract class Template extends Component
} }
// if you use settting translation // if you use settting translation
if ($hideDescription = setting($this->getSettingKey($type, 'hide_item_description'), false)) { if (setting($this->getDocumentSettingKey($type, 'hide_item_description'), false)) {
return $hideDescription; return true;
} }
$hide = $this->getHideFromConfig($type, 'description'); $hide = $this->getHideFromConfig($type, 'description');
@ -624,8 +630,7 @@ abstract class Template extends Component
return $hide; return $hide;
} }
// @todo what return value invoice or always false?? return false;
return setting('invoice.hide_item_description', $hideDescription);
} }
protected function getHideQuantity($type, $hideQuantity) protected function getHideQuantity($type, $hideQuantity)
@ -634,9 +639,11 @@ abstract class Template extends Component
return $hideQuantity; return $hideQuantity;
} }
$hideQuantity = setting($this->getDocumentSettingKey($type, 'quantity_name'), false);
// if you use settting translation // if you use settting translation
if ($hideQuantity = setting($this->getSettingKey($type, 'hide_quantity'), false) && $hideQuantity == 'hide') { if ($hideQuantity === 'hide') {
return $hideQuantity; return true;
} }
$hide = $this->getHideFromConfig($type, 'quantity'); $hide = $this->getHideFromConfig($type, 'quantity');
@ -645,8 +652,7 @@ abstract class Template extends Component
return $hide; return $hide;
} }
// @todo what return value invoice or always false?? return false;
return setting('invoice.quantity_name', $hideQuantity) == 'hide' ? true : false;
} }
protected function getHidePrice($type, $hidePrice) protected function getHidePrice($type, $hidePrice)
@ -655,9 +661,11 @@ abstract class Template extends Component
return $hidePrice; return $hidePrice;
} }
$hidePrice = setting($this->getDocumentSettingKey($type, 'price_name'), false);
// if you use settting translation // if you use settting translation
if ($hidePrice = setting($this->getSettingKey($type, 'hide_price'), false) && $hidePrice == 'hide') { if ($hidePrice === 'hide') {
return $hidePrice; return true;
} }
$hide = $this->getHideFromConfig($type, 'price'); $hide = $this->getHideFromConfig($type, 'price');
@ -666,8 +674,7 @@ abstract class Template extends Component
return $hide; return $hide;
} }
// @todo what return value invoice or always false?? return false;
return setting('invoice.price_name', $hidePrice) == 'hide' ? true : false;
} }
protected function getHideDiscount($type, $hideDiscount) protected function getHideDiscount($type, $hideDiscount)
@ -677,7 +684,7 @@ abstract class Template extends Component
} }
// if you use settting translation // if you use settting translation
if ($hideDiscount = setting($this->getSettingKey($type, 'hide_discount'), false)) { if ($hideDiscount = setting($this->getDocumentSettingKey($type, 'hide_discount'), false)) {
return $hideDiscount; return $hideDiscount;
} }
@ -698,8 +705,8 @@ abstract class Template extends Component
} }
// if you use settting translation // if you use settting translation
if ($hideAmount = setting($this->getSettingKey($type, 'hide_amount'), false)) { if (setting($this->getDocumentSettingKey($type, 'hide_amount'), false)) {
return $hideAmount; return true;
} }
$hide = $this->getHideFromConfig($type, 'amount'); $hide = $this->getHideFromConfig($type, 'amount');
@ -708,8 +715,7 @@ abstract class Template extends Component
return $hide; return $hide;
} }
// @todo what return value invoice or always false?? return false;
return setting('invoice.hide_amount', $hideAmount);
} }
protected function getPrint($print) protected function getPrint($print)

View File

@ -9,7 +9,6 @@ use App\Traits\Transactions;
use App\Utilities\Modules; use App\Utilities\Modules;
use Illuminate\Support\Facades\File; use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\URL; use Illuminate\Support\Facades\URL;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use Intervention\Image\Facades\Image; use Intervention\Image\Facades\Image;
@ -483,7 +482,7 @@ abstract class Show extends Component
return $template; return $template;
} }
$transactionTemplate = setting($this->getSettingKey($type, 'template')) ?: 'default'; $transactionTemplate = setting($this->getTransactionSettingKey($type, 'template')) ?: 'default';
return $transactionTemplate; return $transactionTemplate;
} }
@ -501,7 +500,7 @@ abstract class Show extends Component
if (! empty($media)) { if (! empty($media)) {
$path = $media->getDiskPath(); $path = $media->getDiskPath();
if (Storage::missing($path)) { if (! $media->fileExists()) {
return $logo; return $logo;
} }
} else { } else {
@ -514,7 +513,7 @@ abstract class Show extends Component
$height = setting('invoice.logo_size_height'); $height = setting('invoice.logo_size_height');
if ($media) { if ($media) {
$image->make(Storage::get($path))->resize($width, $height)->encode(); $image->make($media->contents())->resize($width, $height)->encode();
} else { } else {
$image->make($path)->resize($width, $height)->encode(); $image->make($path)->resize($width, $height)->encode();
} }
@ -1114,9 +1113,7 @@ abstract class Show extends Component
return $textRecurringType; return $textRecurringType;
} }
$default_key = config('type.transaction.' . $type . '.translation.transactions'); $translation = config('type.transaction.' . $type . '.translation.transactions');
$translation = $this->getTextFromConfig($type, 'recurring_type', $default_key);
if (! empty($translation)) { if (! empty($translation)) {
return $translation; return $translation;

View File

@ -9,7 +9,6 @@ use App\Traits\Transactions;
use App\Utilities\Modules; use App\Utilities\Modules;
use Illuminate\Support\Facades\File; use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use Intervention\Image\Facades\Image; use Intervention\Image\Facades\Image;
use Intervention\Image\Exception\NotReadableException; use Intervention\Image\Exception\NotReadableException;
@ -277,7 +276,7 @@ abstract class Template extends Component
if (!empty($media)) { if (!empty($media)) {
$path = $media->getDiskPath(); $path = $media->getDiskPath();
if (Storage::missing($path)) { if (! $media->fileExists()) {
return $logo; return $logo;
} }
} else { } else {
@ -290,7 +289,7 @@ abstract class Template extends Component
$height = setting('invoice.logo_size_height'); $height = setting('invoice.logo_size_height');
if ($media) { if ($media) {
$image->make(Storage::get($path))->resize($width, $height)->encode(); $image->make($media->contents())->resize($width, $height)->encode();
} else { } else {
$image->make($path)->resize($width, $height)->encode(); $image->make($path)->resize($width, $height)->encode();
} }

View File

@ -31,7 +31,7 @@ class Bills extends BulkAction
], ],
'cancelled' => [ 'cancelled' => [
'icon' => 'cancel', 'icon' => 'cancel',
'name' => 'general.cancel', 'name' => 'documents.actions.cancel',
'message' => 'bulk_actions.message.cancelled', 'message' => 'bulk_actions.message.cancelled',
'permission' => 'update-purchases-bills', 'permission' => 'update-purchases-bills',
], ],
@ -67,7 +67,7 @@ class Bills extends BulkAction
$bills = $this->getSelectedRecords($request); $bills = $this->getSelectedRecords($request);
foreach ($bills as $bill) { foreach ($bills as $bill) {
if ($bill->status == 'cancelled') { if (in_array($bill->status, ['cancelled', 'draft'])) {
continue; continue;
} }

View File

@ -31,7 +31,7 @@ class Invoices extends BulkAction
], ],
'cancelled' => [ 'cancelled' => [
'icon' => 'cancel', 'icon' => 'cancel',
'name' => 'general.cancel', 'name' => 'documents.actions.cancel',
'message' => 'bulk_actions.message.cancelled', 'message' => 'bulk_actions.message.cancelled',
'permission' => 'update-sales-invoices', 'permission' => 'update-sales-invoices',
], ],
@ -67,7 +67,7 @@ class Invoices extends BulkAction
$invoices = $this->getSelectedRecords($request); $invoices = $this->getSelectedRecords($request);
foreach ($invoices as $invoice) { foreach ($invoices as $invoice) {
if ($invoice->status == 'cancelled') { if (in_array($invoice->status, ['cancelled', 'draft'])) {
continue; continue;
} }

View File

@ -1,29 +0,0 @@
<?php
namespace App\Classifiers;
use Wnx\LaravelStats\ReflectionClass;
use Wnx\LaravelStats\Contracts\Classifier;
class Transformer implements Classifier
{
public function name(): string
{
return 'Transformers';
}
public function satisfies(ReflectionClass $class): bool
{
return $class->isSubclassOf(\League\Fractal\TransformerAbstract::class);
}
public function countsTowardsApplicationCode(): bool
{
return true;
}
public function countsTowardsTests(): bool
{
return false;
}
}

View File

@ -125,6 +125,6 @@ class DownloadModule extends Command
$version = Versions::getLatestVersion($url, $current); $version = Versions::getLatestVersion($url, $current);
} }
return $version; return $version?->latest;
} }
} }

View File

@ -71,12 +71,18 @@ class RecurringCheck extends Command
$company_name = !empty($recur->company->name) ? $recur->company->name : 'Missing Company Name : ' . $recur->company->id; $company_name = !empty($recur->company->name) ? $recur->company->name : 'Missing Company Name : ' . $recur->company->id;
$template = $recur->recurable()->where('company_id', $recur->company_id)->first();
// Check if company is disabled // Check if company is disabled
if (! $recur->company->enabled) { if (! $recur->company->enabled) {
$this->info($company_name . ' company is disabled. Skipping...'); $this->info($company_name . ' company is disabled. Skipping...');
if (Date::parse($recur->company->updated_at)->format('Y-m-d') > Date::now()->subMonth(3)->format('Y-m-d')) { if (Date::parse($recur->company->updated_at)->format('Y-m-d') > Date::now()->subMonth(3)->format('Y-m-d')) {
$recur->delete(); $recur->delete();
if ($template) {
$template->delete();
}
} }
continue; continue;
@ -98,12 +104,16 @@ class RecurringCheck extends Command
$recur->delete(); $recur->delete();
if ($template) {
$template->delete();
}
continue; continue;
} }
company($recur->company_id)->makeCurrent(); company($recur->company_id)->makeCurrent();
if (! $template = $recur->recurable) { if (! $template) {
$this->info('Missing model.'); $this->info('Missing model.');
$recur->delete(); $recur->delete();

View File

@ -68,6 +68,14 @@ class Update extends Command
$this->old = $this->getOldVersion(); $this->old = $this->getOldVersion();
if (version_compare($this->old, $this->new, '>=')) {
$message = 'The current version for the ' . $this->alias . ' is the latest version!';
$this->info($message);
return self::CMD_SUCCESS;
}
company($this->company)->makeCurrent(); company($this->company)->makeCurrent();
if (!$path = $this->download()) { if (!$path = $this->download()) {
@ -91,7 +99,7 @@ class Update extends Command
public function getNewVersion() public function getNewVersion()
{ {
return ($this->argument('new') == 'latest') ? Versions::latest($this->alias) : $this->argument('new'); return ($this->argument('new') == 'latest') ? Versions::latest($this->alias)?->latest : $this->argument('new');
} }
public function getOldVersion() public function getOldVersion()

View File

@ -0,0 +1,23 @@
<?php
namespace App\Events\Common;
use App\Abstracts\Event;
class DatesFormating extends Event
{
public $columns;
public $request;
/**
* Create a new event instance.
*
* @param $request
*/
public function __construct($columns, $request)
{
$this->columns = $columns;
$this->request = $request;
}
}

View File

@ -0,0 +1,20 @@
<?php
namespace App\Events\Document;
use App\Abstracts\Event;
class DocumentDeleted extends Event
{
public $document;
/**
* Create a new event instance.
*
* @param $document
*/
public function __construct($document)
{
$this->document = $document;
}
}

View File

@ -0,0 +1,20 @@
<?php
namespace App\Events\Document;
use App\Abstracts\Event;
class DocumentDeleting extends Event
{
public $document;
/**
* Create a new event instance.
*
* @param $document
*/
public function __construct($document)
{
$this->document = $document;
}
}

View File

@ -0,0 +1,20 @@
<?php
namespace App\Events\Document;
use App\Abstracts\Event;
class DocumentSending extends Event
{
public $document;
/**
* Create a new event instance.
*
* @param $document
*/
public function __construct($document)
{
$this->document = $document;
}
}

View File

@ -0,0 +1,51 @@
<?php
namespace App\Events\Email;
use App\Abstracts\Event;
use App\Models\Auth\User;
use App\Models\Common\Contact;
class InvalidEmailDetected extends Event
{
public $email;
public $error;
public $contact = null;
public $user = null;
public function __construct(string $email, string $error)
{
$this->email = $email;
$this->error = $error;
$this->setContact();
$this->setUser();
}
public function setContact()
{
$contact = Contact::email($this->email)->enabled()->first();
if (empty($contact)) {
return;
}
$this->contact = $contact;
}
public function setUser()
{
$user = User::email($this->email)->enabled()->first();
if (empty($user)) {
return;
}
$this->user = $user;
}
}

View File

@ -0,0 +1,15 @@
<?php
namespace App\Events\Email;
use App\Abstracts\Event;
class TooManyEmailsSent extends Event
{
public $user_id;
public function __construct(int $user_id)
{
$this->user_id = $user_id;
}
}

View File

@ -3,6 +3,7 @@
namespace App\Exceptions; namespace App\Exceptions;
use Akaunting\Money\Exceptions\UnexpectedAmountException; use Akaunting\Money\Exceptions\UnexpectedAmountException;
use App\Events\Email\InvalidEmailDetected;
use App\Exceptions\Http\Resource as ResourceException; use App\Exceptions\Http\Resource as ResourceException;
use Illuminate\Auth\AuthenticationException; use Illuminate\Auth\AuthenticationException;
use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Database\Eloquent\ModelNotFoundException;
@ -15,6 +16,7 @@ use Illuminate\View\ViewException;
use Symfony\Component\Debug\Exception\FatalThrowableError; use Symfony\Component\Debug\Exception\FatalThrowableError;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Mailer\Exception\HttpTransportException as MailerHttpTransportException;
use Throwable; use Throwable;
class Handler extends ExceptionHandler class Handler extends ExceptionHandler
@ -72,6 +74,14 @@ class Handler extends ExceptionHandler
*/ */
public function report(Throwable $exception) public function report(Throwable $exception)
{ {
if ($exception instanceof MailerHttpTransportException) {
$email = $this->handleMailerExceptions($exception);
if (! empty($email)) {
return;
}
}
parent::report($exception); parent::report($exception);
} }
@ -194,6 +204,24 @@ class Handler extends ExceptionHandler
} }
} }
if ($exception instanceof MailerHttpTransportException) {
$email = $this->handleMailerExceptions($exception);
if (! empty($email)) {
$message = trans('notifications.menu.invalid_email.description', ['email' => $email]);
if ($request->ajax()) {
return response()->json([
'error' => $message,
], $exception->getCode());
}
return response()->view('errors.403', [
'message' => $message,
], $exception->getCode());
}
}
return parent::render($request, $exception); return parent::render($request, $exception);
} }
@ -214,6 +242,28 @@ class Handler extends ExceptionHandler
return new Response($response, $this->getStatusCode($exception), $this->getHeaders($exception)); return new Response($response, $this->getStatusCode($exception), $this->getHeaders($exception));
} }
protected function handleMailerExceptions(MailerHttpTransportException $exception): string
{
/**
* Couldn't access the SentMessage object to get the email address
* https://symfony.com/doc/current/mailer.html#debugging-emails
*
* https://codespeedy.com/extract-email-addresses-from-a-string-in-php
* https://phpliveregex.com/p/IMG
*/
preg_match("/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}/", $exception->getMessage(), $matches);
if (empty($matches[0])) {
return '';
}
$email = $matches[0];
event(new InvalidEmailDetected($email, $exception->getMessage()));
return $email;
}
/** /**
* Prepare the replacements array by gathering the keys and values. * Prepare the replacements array by gathering the keys and values.
* *

View File

@ -22,6 +22,8 @@ class BillItems extends Export
$model->bill_number = $document->document_number; $model->bill_number = $document->document_number;
$model->item_name = $model->item->name; $model->item_name = $model->item->name;
$model->item_description = $model->item->description;
$model->item_type = $model->item->type;
return parent::map($model); return parent::map($model);
} }
@ -31,6 +33,8 @@ class BillItems extends Export
return [ return [
'bill_number', 'bill_number',
'item_name', 'item_name',
'item_description',
'item_type',
'quantity', 'quantity',
'price', 'price',
'total', 'total',

View File

@ -22,6 +22,8 @@ class Customers extends Export
$model->country = $country; $model->country = $country;
$model->can_login = $model->user_id ? true : false;
return parent::map($model); return parent::map($model);
} }
@ -41,6 +43,7 @@ class Customers extends Export
'currency_code', 'currency_code',
'reference', 'reference',
'enabled', 'enabled',
'can_login',
]; ];
} }
} }

View File

@ -22,6 +22,8 @@ class InvoiceItems extends Export
$model->invoice_number = $document->document_number; $model->invoice_number = $document->document_number;
$model->item_name = $model->item->name; $model->item_name = $model->item->name;
$model->item_description = $model->item->description;
$model->item_type = $model->item->type;
return parent::map($model); return parent::map($model);
} }
@ -31,6 +33,8 @@ class InvoiceItems extends Export
return [ return [
'invoice_number', 'invoice_number',
'item_name', 'item_name',
'item_description',
'item_type',
'quantity', 'quantity',
'price', 'price',
'total', 'total',

View File

@ -5,7 +5,7 @@ namespace App\Http\Controllers\Auth;
use App\Abstracts\Http\Controller; use App\Abstracts\Http\Controller;
use Illuminate\Foundation\Auth\SendsPasswordResetEmails; use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
use Illuminate\Http\Request; use App\Http\Requests\Auth\Forgot as Request;
use Illuminate\Support\Facades\Password; use Illuminate\Support\Facades\Password;
class Forgot extends Controller class Forgot extends Controller
@ -42,13 +42,11 @@ class Forgot extends Controller
/** /**
* Send a reset link to the given user. * Send a reset link to the given user.
* *
* @param \Illuminate\Http\Request $request * @param \App\Http\Requests\Auth\Forgot $request
* @return \Illuminate\Http\RedirectResponse * @return \Illuminate\Http\RedirectResponse
*/ */
public function store(Request $request) public function store(Request $request)
{ {
$this->validateEmail($request);
// We will send the password reset link to this user. Once we have attempted // We will send the password reset link to this user. Once we have attempted
// to send the link, we will examine the response then see the message we // to send the link, we will examine the response then see the message we
// need to show to the user. Finally, we'll send out a proper response. // need to show to the user. Finally, we'll send out a proper response.
@ -96,7 +94,7 @@ class Forgot extends Controller
'error' => true, 'error' => true,
'message' => trans('passwords.user'), 'message' => trans('passwords.user'),
'data' => null, 'data' => null,
'redirect' => null, 'redirect' => route('forgot'),
]; ];
return response()->json($response); return response()->json($response);

View File

@ -4,7 +4,8 @@ namespace App\Http\Controllers\Auth;
use App\Abstracts\Http\Controller; use App\Abstracts\Http\Controller;
use Illuminate\Foundation\Auth\ResetsPasswords; use Illuminate\Foundation\Auth\ResetsPasswords;
use Illuminate\Http\Request; use Illuminate\Http\Request as BaseRequest;
use App\Http\Requests\Auth\Reset as Request;
use Illuminate\Support\Facades\Password; use Illuminate\Support\Facades\Password;
use Illuminate\Support\Str; use Illuminate\Support\Str;
@ -29,17 +30,22 @@ class Reset extends Controller
$this->middleware('guest'); $this->middleware('guest');
} }
public function create(Request $request, $token = null) public function create(BaseRequest $request, $token = null)
{ {
return view('auth.reset.create')->with( return view('auth.reset.create')->with(
['token' => $token, 'email' => $request->email] ['token' => $token, 'email' => $request->email]
); );
} }
/**
* Send a reset link to the given user.
*
* @param \App\Http\Requests\Auth\Reset $request
*
* @return \Illuminate\Http\JsonResponse
*/
public function store(Request $request) public function store(Request $request)
{ {
$this->validate($request, $this->rules(), $this->validationErrorMessages());
// Here we will attempt to reset the user's password. If it is successful we // Here we will attempt to reset the user's password. If it is successful we
// will update the password on an actual user model and persist it to the // will update the password on an actual user model and persist it to the
// database. Otherwise we will parse the error and return the response. // database. Otherwise we will parse the error and return the response.

View File

@ -47,9 +47,19 @@ class Users extends Controller
* *
* @return Response * @return Response
*/ */
public function show() public function show(User $user)
{ {
return redirect()->route('users.index'); $u = new \stdClass();
$u->role = $user->roles()->first();
$u->landing_pages = [];
event(new LandingPageShowing($u));
$landing_pages = $u->landing_pages;
$companies = $user->companies()->collect();
return view('auth.users.show', compact('user', 'landing_pages', 'companies'));
} }
/** /**
@ -67,7 +77,13 @@ class Users extends Controller
$landing_pages = $u->landing_pages; $landing_pages = $u->landing_pages;
$roles = Role::all()->reject(function ($r) { $roles = Role::all()->reject(function ($r) {
return $r->hasPermission('read-client-portal'); $status = $r->hasPermission('read-client-portal');
if ($r->name == 'employee') {
$status = true;
}
return $status;
})->pluck('display_name', 'id'); })->pluck('display_name', 'id');
$companies = user()->companies()->take(setting('default.select_limit'))->get()->sortBy('name')->pluck('name', 'id'); $companies = user()->companies()->take(setting('default.select_limit'))->get()->sortBy('name')->pluck('name', 'id');
@ -89,7 +105,7 @@ class Users extends Controller
$response = $this->ajaxDispatch(new CreateUser($request)); $response = $this->ajaxDispatch(new CreateUser($request));
if ($response['success']) { if ($response['success']) {
$response['redirect'] = route('users.index'); $response['redirect'] = route('users.show', $response['data']->id);
$message = trans('messages.success.invited', ['type' => trans_choice('general.users', 1)]); $message = trans('messages.success.invited', ['type' => trans_choice('general.users', 1)]);
@ -129,12 +145,21 @@ class Users extends Controller
if ($user->isCustomer()) { if ($user->isCustomer()) {
// Show only roles with customer permission // Show only roles with customer permission
$roles = Role::all()->reject(function ($r) { $roles = Role::all()->reject(function ($r) {
return !$r->hasPermission('read-client-portal'); return ! $r->hasPermission('read-client-portal');
})->pluck('display_name', 'id'); })->pluck('display_name', 'id');
} else if ($user->isEmployee()) {
// Show only roles with employee permission
$roles = Role::where('name', 'employee')->get()->pluck('display_name', 'id');
} else { } else {
// Don't show roles with customer permission // Don't show roles with customer permission
$roles = Role::all()->reject(function ($r) { $roles = Role::all()->reject(function ($r) {
return $r->hasPermission('read-client-portal'); $status = $r->hasPermission('read-client-portal');
if ($r->name == 'employee') {
$status = true;
}
return $status;
})->pluck('display_name', 'id'); })->pluck('display_name', 'id');
} }
@ -176,7 +201,7 @@ class Users extends Controller
$response = $this->ajaxDispatch(new UpdateUser($user, $request)); $response = $this->ajaxDispatch(new UpdateUser($user, $request));
if ($response['success']) { if ($response['success']) {
$response['redirect'] = user()->can('read-auth-users') ? route('users.index') : route('users.edit', $user->id); $response['redirect'] = user()->can('read-auth-users') ? route('users.show', $user->id) : route('users.edit', $user->id);
$message = trans('messages.success.updated', ['type' => $user->name]); $message = trans('messages.success.updated', ['type' => $user->name]);
@ -341,8 +366,6 @@ class Users extends Controller
{ {
$response = $this->ajaxDispatch(new CreateInvitation($user, company())); $response = $this->ajaxDispatch(new CreateInvitation($user, company()));
$response['redirect'] = route('users.index');
if ($response['success']) { if ($response['success']) {
$message = trans('messages.success.invited', ['type' => trans_choice('general.users', 1)]); $message = trans('messages.success.invited', ['type' => trans_choice('general.users', 1)]);
@ -353,7 +376,7 @@ class Users extends Controller
flash($message)->error()->important(); flash($message)->error()->important();
} }
return response()->json($response); return redirect()->route('users.index');
} }
/** /**

View File

@ -35,16 +35,16 @@ class Accounts extends Controller
*/ */
public function show(Account $account) public function show(Account $account)
{ {
$transactions = Transaction::with('category', 'contact', 'document')->where('account_id', $account->id)->collect(['paid_at'=> 'desc']); $transactions = Transaction::with('category', 'contact', 'contact.media', 'document', 'document.totals', 'document.media', 'recurring', 'media')->where('account_id', $account->id)->collect(['paid_at'=> 'desc']);
$transfers = Transfer::with('expense_transaction', 'expense_transaction.account', 'income_transaction', 'income_transaction.account') $transfers = Transfer::with('expense_transaction', 'expense_transaction.account', 'income_transaction', 'income_transaction.account')
->whereHas('expense_transaction', fn ($query) => $query->where('account_id', $account->id)) ->whereHas('expense_transaction', fn ($query) => $query->where('account_id', $account->id))
->orWhereHas('income_transaction', fn ($query) => $query->where('account_id', $account->id)) ->orWhereHas('income_transaction', fn ($query) => $query->where('account_id', $account->id))
->collect(['expense_transaction.paid_at' => 'desc']); ->collect(['expense_transaction.paid_at' => 'desc']);
$incoming_amount = money($account->income_balance, $account->currency_code, true); $incoming_amount = money($account->income_balance, $account->currency_code);
$outgoing_amount = money($account->expense_balance, $account->currency_code, true); $outgoing_amount = money($account->expense_balance, $account->currency_code);
$current_amount = money($account->balance, $account->currency_code, true); $current_amount = money($account->balance, $account->currency_code);
$summary_amounts = [ $summary_amounts = [
'incoming_exact' => $incoming_amount->format(), 'incoming_exact' => $incoming_amount->format(),

View File

@ -24,8 +24,8 @@ class Reconciliations extends Controller
{ {
$reconciliations = Reconciliation::with('account')->collect(); $reconciliations = Reconciliation::with('account')->collect();
$reconciled_amount = money($reconciliations->where('reconciled', 1)->sum('closing_balance'), default_currency(), true); $reconciled_amount = money($reconciliations->where('reconciled', 1)->sum('closing_balance'));
$in_progress_amount = money($reconciliations->where('reconciled', 0)->sum('closing_balance'), default_currency(), true); $in_progress_amount = money($reconciliations->where('reconciled', 0)->sum('closing_balance'));
$summary_amounts = [ $summary_amounts = [
'amount_exact' => $reconciled_amount->format(), 'amount_exact' => $reconciled_amount->format(),
@ -246,9 +246,9 @@ class Reconciliations extends Controller
$difference = $closing_balance - $cleared_amount; $difference = $closing_balance - $cleared_amount;
$json->closing_balance = money($closing_balance, $currency_code, true)->format(); $json->closing_balance = money($closing_balance, $currency_code)->format();
$json->cleared_amount = money($cleared_amount, $currency_code, true)->format(); $json->cleared_amount = money($cleared_amount, $currency_code)->format();
$json->difference = money($difference, $currency_code, true)->format(); $json->difference = money($difference, $currency_code)->format();
$json->difference_raw = (int) $difference; $json->difference_raw = (int) $difference;
return response()->json($json); return response()->json($json);

View File

@ -63,9 +63,9 @@ class RecurringTransactions extends Controller
*/ */
public function create() public function create()
{ {
$type = request()->get('type', 'income-recurring'); $type = $this->getTypeRecurringTransaction(request()->get('type', 'income-recurring'));
$real_type = request()->get('real_type', $this->getRealTypeOfRecurringTransaction($type)); $real_type = $this->getTypeTransaction(request()->get('real_type', $this->getRealTypeOfRecurringTransaction($type)));
$contact_type = config('type.transaction.' . $real_type . '.contact_type'); $contact_type = config('type.transaction.' . $real_type . '.contact_type', 'customer');
$number = $this->getNextTransactionNumber('-recurring'); $number = $this->getNextTransactionNumber('-recurring');
@ -139,8 +139,8 @@ class RecurringTransactions extends Controller
public function edit(Transaction $recurring_transaction) public function edit(Transaction $recurring_transaction)
{ {
$type = $recurring_transaction->type; $type = $recurring_transaction->type;
$real_type = request()->get('real_type', $this->getRealTypeOfRecurringTransaction($type)); $real_type = $this->getTypeTransaction(request()->get('real_type', $this->getRealTypeOfRecurringTransaction($type)));
$contact_type = config('type.transaction.' . $real_type . '.contact_type'); $contact_type = config('type.transaction.' . $real_type . '.contact_type', 'customer');
$number = $this->getNextTransactionNumber('-recurring'); $number = $this->getNextTransactionNumber('-recurring');

View File

@ -56,9 +56,9 @@ class Transactions extends Controller
$totals['profit'] = $totals['income'] - $totals['expense']; $totals['profit'] = $totals['income'] - $totals['expense'];
$incoming_amount = money($totals['income'], default_currency(), true); $incoming_amount = money($totals['income']);
$expense_amount = money($totals['expense'], default_currency(), true); $expense_amount = money($totals['expense']);
$profit_amount = money($totals['profit'], default_currency(), true); $profit_amount = money($totals['profit']);
$summary_amounts = [ $summary_amounts = [
'incoming_exact' => $incoming_amount->format(), 'incoming_exact' => $incoming_amount->format(),
@ -98,10 +98,10 @@ class Transactions extends Controller
*/ */
public function create() public function create()
{ {
$type = request()->get('type', 'income'); $type = $this->getTypeTransaction(request()->get('type', 'income'));
$real_type = $this->getRealTypeTransaction($type); $real_type = $this->getRealTypeTransaction($type);
$number = $this->getNextTransactionNumber(); $number = $this->getNextTransactionNumber($type);
$contact_type = config('type.transaction.' . $type . '.contact_type'); $contact_type = config('type.transaction.' . $type . '.contact_type');

View File

@ -61,19 +61,28 @@ class BulkActions extends Controller
$result = $bulk_actions->{$handle}($request); $result = $bulk_actions->{$handle}($request);
$message = trans($bulk_actions->messages['general'], ['type' => $handle, 'count' => count($request->get('selected'))]); $count = count($request->get('selected'));
$not_passed = 0;
if (array_key_exists($handle, $bulk_actions->messages)) { flash()->messages->each(function ($message) use (&$not_passed) {
if (in_array($message->level, ['danger', 'warning'])) {
$not_passed++;
}
});
$message = trans($bulk_actions->messages['general'], ['type' => $handle, 'count' => $count - $not_passed]);
if (array_key_exists($handle, $bulk_actions->messages) && $not_passed === 0) {
$message = trans($bulk_actions->messages[$handle], ['type' => $page]); $message = trans($bulk_actions->messages[$handle], ['type' => $page]);
} }
if (! empty($result) && ($result instanceof \Symfony\Component\HttpFoundation\BinaryFileResponse)) { $level = $not_passed > 0 ? 'info' : 'success';
flash($message)->success();
flash($message)->{$level}();
if (! empty($result) && ($result instanceof \Symfony\Component\HttpFoundation\BinaryFileResponse)) {
return $result; return $result;
} elseif (! empty($result) && ($result instanceof RedirectResponse)) { } elseif (! empty($result) && ($result instanceof RedirectResponse)) {
flash($message)->success();
return response()->json([ return response()->json([
'success' => true, 'success' => true,
'redirect' => $result->getTargetUrl(), 'redirect' => $result->getTargetUrl(),
@ -82,8 +91,6 @@ class BulkActions extends Controller
'message' => '' 'message' => ''
]); ]);
} else { } else {
flash($message)->success();
return response()->json([ return response()->json([
'success' => true, 'success' => true,
'redirect' => true, 'redirect' => true,

View File

@ -16,6 +16,15 @@ class Companies extends Controller
{ {
use Uploads, Users; use Uploads, Users;
public function __construct()
{
// Add CRUD permission checks to all methods only remove index method for all companies list.
$this->middleware('permission:create-common-companies')->only('create', 'store', 'duplicate', 'import');
$this->middleware('permission:read-common-companies')->only('show', 'edit', 'export');
$this->middleware('permission:update-common-companies')->only('update', 'enable', 'disable');
$this->middleware('permission:delete-common-companies')->only('destroy');
}
/** /**
* Display a listing of the resource. * Display a listing of the resource.
* *

View File

@ -34,6 +34,22 @@ class Uploads extends Controller
return $this->streamMedia($media); return $this->streamMedia($media);
} }
public function inline($id)
{
try {
$media = Media::find($id);
} catch (\Exception $e) {
return response(null, 204);
}
// Get file path
if (!$this->getMediaPathOnStorage($media)) {
return response(null, 204);
}
return $this->streamMedia($media, 'inline');
}
/** /**
* Get the specified resource. * Get the specified resource.
* *

View File

@ -15,7 +15,12 @@ class Database extends Controller
*/ */
public function create() public function create()
{ {
return view('install.database.create'); return view('install.database.create', [
'host' => env('DB_HOST' , 'localhost'),
'username' => env('DB_USERNAME', ''),
'password' => env('DB_PASSWORD', ''),
'database' => env('DB_DATABASE', ''),
]);
} }
/** /**
@ -34,9 +39,10 @@ class Database extends Controller
$database = $request['database']; $database = $request['database'];
$username = $request['username']; $username = $request['username'];
$password = $request['password']; $password = $request['password'];
$prefix = config("database.connections.$connection.prefix", null);
// Check database connection // Check database connection
if (!Installer::createDbTables($host, $port, $database, $username, $password)) { if (!Installer::createDbTables($host, $port, $database, $username, $password, $prefix)) {
$response = [ $response = [
'status' => null, 'status' => null,
'success' => false, 'success' => false,

View File

@ -14,7 +14,15 @@ class Language extends Controller
*/ */
public function create() public function create()
{ {
return view('install.language.create'); $locale = config('app.locale');
$lang_allowed = language()->allowed();
if (! $locale || ! array_key_exists($locale, $lang_allowed)) {
$locale = 'en-GB';
}
return view('install.language.create', compact('locale', 'lang_allowed'));
} }
/** /**

View File

@ -29,11 +29,13 @@ class Settings extends Controller
public function store(Request $request) public function store(Request $request)
{ {
DB::transaction(function () use ($request) { DB::transaction(function () use ($request) {
$locale = session('locale') ?? config('app.locale');
// Create company // Create company
Installer::createCompany($request->get('company_name'), $request->get('company_email'), session('locale')); Installer::createCompany($request->get('company_name'), $request->get('company_email'), $locale);
// Create user // Create user
Installer::createUser($request->get('user_email'), $request->get('user_password'), session('locale')); Installer::createUser($request->get('user_email'), $request->get('user_password'), $locale);
}); });
// Make the final touches // Make the final touches

View File

@ -48,7 +48,9 @@ class Updates extends Controller
$m->name = $row->getName(); $m->name = $row->getName();
$m->alias = $row->get('alias'); $m->alias = $row->get('alias');
$m->installed = $row->get('version'); $m->installed = $row->get('version');
$m->latest = $updates[$alias]; $m->latest = $updates[$alias]->latest;
$m->errors = $updates[$alias]->errors;
$m->message = $updates[$alias]->message;
$modules[] = $m; $modules[] = $m;
} }

View File

@ -64,7 +64,7 @@ class Currencies extends Controller
*/ */
public function store(Request $request) public function store(Request $request)
{ {
$currency = config('money.' . $request->get('code')); $currency = config('money.currencies.' . $request->get('code'));
$request['precision'] = (int) $currency['precision']; $request['precision'] = (int) $currency['precision'];
$request['symbol'] = $currency['symbol']; $request['symbol'] = $currency['symbol'];

View File

@ -32,22 +32,22 @@ class DocumentItemColumns extends Controller
$item_names = [ $item_names = [
'hide' => trans('settings.invoice.hide.item_name'), 'hide' => trans('settings.invoice.hide.item_name'),
'settings.invoice.item' => trans('settings.' . $type . '.item'), 'settings.invoice.item' => trans('settings.invoice.item'),
'settings.invoice.product' => trans('settings.' . $type . '.product'), 'settings.invoice.product' => trans('settings.invoice.product'),
'settings.invoice.service' => trans('settings.' . $type . '.service'), 'settings.invoice.service' => trans('settings.invoice.service'),
'custom' => trans('settings.invoice.custom'), 'custom' => trans('settings.invoice.custom'),
]; ];
$price_names = [ $price_names = [
'hide' => trans('settings.invoice.hide.price'), 'hide' => trans('settings.invoice.hide.price'),
'settings.invoice.price' => trans('settings.' . $type . '.price'), 'settings.invoice.price' => trans('settings.invoice.price'),
'settings.invoice.rate' => trans('settings.' . $type . '.rate'), 'settings.invoice.rate' => trans('settings.invoice.rate'),
'custom' => trans('settings.invoice.custom'), 'custom' => trans('settings.invoice.custom'),
]; ];
$quantity_names = [ $quantity_names = [
'hide' => trans('settings.invoice.hide.quantity'), 'hide' => trans('settings.invoice.hide.quantity'),
'settings.invoice.quantity' => trans('settings.' . $type . '.quantity'), 'settings.invoice.quantity' => trans('settings.invoice.quantity'),
'custom' => trans('settings.invoice.custom'), 'custom' => trans('settings.invoice.custom'),
]; ];
@ -60,17 +60,17 @@ class DocumentItemColumns extends Controller
'90' => trans('settings.invoice.due_days', ['days' => 90]), '90' => trans('settings.invoice.due_days', ['days' => 90]),
]; ];
$item_name = setting($this->getSettingKey($type, 'item_name')); $item_name = setting($this->getDocumentSettingKey($type, 'item_name'));
$item_name_input = setting($this->getSettingKey($type, 'item_name_input')); $item_name_input = setting($this->getDocumentSettingKey($type, 'item_name_input'));
$price_name = setting($this->getSettingKey($type, 'price_name')); $price_name = setting($this->getDocumentSettingKey($type, 'price_name'));
$price_name_input = setting($this->getSettingKey($type, 'price_name_input')); $price_name_input = setting($this->getDocumentSettingKey($type, 'price_name_input'));
$quantity_name = setting($this->getSettingKey($type, 'quantity_name')); $quantity_name = setting($this->getDocumentSettingKey($type, 'quantity_name'));
$quantity_name_input = setting($this->getSettingKey($type, 'quantity_name_input')); $quantity_name_input = setting($this->getDocumentSettingKey($type, 'quantity_name_input'));
$hide_item_name = setting($this->getSettingKey($type, 'hide_item_name')); $hide_item_name = setting($this->getDocumentSettingKey($type, 'hide_item_name'));
$hide_item_description = setting($this->getSettingKey($type, 'hide_item_description')); $hide_item_description = setting($this->getDocumentSettingKey($type, 'hide_item_description'));
$hide_quantity = setting($this->getSettingKey($type, 'hide_quantity')); $hide_quantity = setting($this->getDocumentSettingKey($type, 'hide_quantity'));
$hide_price = setting($this->getSettingKey($type, 'hide_price')); $hide_price = setting($this->getDocumentSettingKey($type, 'hide_price'));
$hide_amount = setting($this->getSettingKey($type, 'hide_amount')); $hide_amount = setting($this->getDocumentSettingKey($type, 'hide_amount'));
$html = view('modals.documents.item_columns', compact( $html = view('modals.documents.item_columns', compact(
'type', 'type',
@ -117,7 +117,7 @@ class DocumentItemColumns extends Controller
} }
foreach ($fields as $key => $value) { foreach ($fields as $key => $value) {
$real_key = $this->getSettingKey($type, $key); $real_key = $this->getDocumentSettingKey($type, $key);
// Don't process unwanted keys // Don't process unwanted keys
if (in_array($key, $this->skip_keys)) { if (in_array($key, $this->skip_keys)) {

View File

@ -51,9 +51,9 @@ class DocumentTransactions extends Controller
$document->{$document_total->code} = $document_total->amount; $document->{$document_total->code} = $document_total->amount;
} }
$total = money($document->total, $currency->code, true)->format(); $total = money($document->total, $currency->code)->format();
$document->grand_total = money($total, $currency->code)->getAmount(); $document->grand_total = money($total, $currency->code, false)->getAmount();
if (! empty($paid)) { if (! empty($paid)) {
$document->grand_total = round($document->total - $paid, $currency->precision); $document->grand_total = round($document->total - $paid, $currency->precision);
@ -140,7 +140,7 @@ class DocumentTransactions extends Controller
$number = $transaction->number; $number = $transaction->number;
$document->grand_total = money($transaction->amount, $currency->code)->getAmount(); $document->grand_total = money($transaction->amount, $currency->code, false)->getAmount();
$document->paid_at = $transaction->paid_at; $document->paid_at = $transaction->paid_at;

View File

@ -242,16 +242,30 @@ class Item extends Controller
$this->dispatch(new InstallModule($request['alias'], company_id())); $this->dispatch(new InstallModule($request['alias'], company_id()));
$name = module($request['alias'])->getName(); $name = module($request['alias'])->getName();
$module_routes = module_attribute($request['alias'], 'routes', []);
$message = trans('modules.installed', ['module' => $name]); $message = trans('modules.installed', ['module' => $name]);
flash($message)->success(); flash($message)->success();
$redirect = route('apps.app.show', $request['alias']);
// Get module.json redirect route
if (! empty($module_routes['redirect_after_install'])) {
if (is_array($module_routes['redirect_after_install'])) {
$route = array_shift($module_routes['redirect_after_install']);
$redirect = route($route, $module_routes['redirect_after_install']);
} else {
$redirect = route($module_routes['redirect_after_install']);
}
}
$json = [ $json = [
'success' => true, 'success' => true,
'error' => false, 'error' => false,
'message' => null, 'message' => null,
'redirect' => route('apps.app.show', $request['alias']), 'redirect' => $redirect,
'data' => [ 'data' => [
'name' => $name, 'name' => $name,
'alias' => $request['alias'], 'alias' => $request['alias'],

View File

@ -194,20 +194,19 @@ class Tiles extends Controller
case 'paid': case 'paid':
$response = $this->getPaidModules($data); $response = $this->getPaidModules($data);
$last_page = $response->last_page; $last_page = ! empty($response) ? $response->last_page : 1;
$modules = $this->prepareModules($response); $modules = $this->prepareModules($response);
break; break;
case 'new': case 'new':
$response = $this->getNewModules($data); $response = $this->getNewModules($data);
$last_page = $response->last_page; $last_page = ! empty($response) ? $response->last_page : 1;
$modules = $this->prepareModules($response); $modules = $this->prepareModules($response);
break; break;
case 'free': case 'free':
$response = $this->getFreeModules($data); $response = $this->getFreeModules($data);
$last_page = $response->last_page; $last_page = ! empty($response) ? $response->last_page : 1;
$modules = $this->prepareModules($response); $modules = $this->prepareModules($response);
break; break;
case 'search': case 'search':
@ -215,7 +214,7 @@ class Tiles extends Controller
$response = $this->getSearchModules($data); $response = $this->getSearchModules($data);
$last_page = $response->last_page; $last_page = ! empty($response) ? $response->last_page : 1;
$modules = $this->prepareModules($response); $modules = $this->prepareModules($response);
break; break;
} }

View File

@ -7,7 +7,6 @@ use App\Exports\Purchases\Bills as Export;
use App\Http\Requests\Common\Import as ImportRequest; use App\Http\Requests\Common\Import as ImportRequest;
use App\Http\Requests\Document\Document as Request; use App\Http\Requests\Document\Document as Request;
use App\Imports\Purchases\Bills as Import; use App\Imports\Purchases\Bills as Import;
use App\Jobs\Banking\CreateBankingDocumentTransaction;
use App\Jobs\Document\CreateDocument; use App\Jobs\Document\CreateDocument;
use App\Jobs\Document\DeleteDocument; use App\Jobs\Document\DeleteDocument;
use App\Jobs\Document\DuplicateDocument; use App\Jobs\Document\DuplicateDocument;
@ -31,7 +30,7 @@ class Bills extends Controller
*/ */
public function index() public function index()
{ {
$bills = Document::bill()->with('contact', 'transactions')->collect(['issued_at' => 'desc']); $bills = Document::bill()->with('contact', 'items', 'item_taxes', 'last_history', 'transactions', 'totals', 'histories', 'media')->collect(['issued_at' => 'desc']);
return $this->response('purchases.bills.index', compact('bills')); return $this->response('purchases.bills.index', compact('bills'));
} }

View File

@ -30,7 +30,7 @@ class Vendors extends Controller
*/ */
public function index() public function index()
{ {
$vendors = Contact::with('bills.transactions')->vendor()->collect(); $vendors = Contact::with('bills.histories', 'bills.totals', 'bills.transactions', 'media')->vendor()->collect();
return $this->response('purchases.vendors.index', compact('vendors')); return $this->response('purchases.vendors.index', compact('vendors'));
} }
@ -152,7 +152,7 @@ class Vendors extends Controller
$response = $this->ajaxDispatch(new UpdateContact($vendor, $request)); $response = $this->ajaxDispatch(new UpdateContact($vendor, $request));
if ($response['success']) { if ($response['success']) {
$response['redirect'] = route('vendors.index'); $response['redirect'] = route('vendors.show', $response['data']->id);
$message = trans('messages.success.updated', ['type' => $vendor->name]); $message = trans('messages.success.updated', ['type' => $vendor->name]);

View File

@ -30,7 +30,7 @@ class Customers extends Controller
*/ */
public function index() public function index()
{ {
$customers = Contact::customer()->with('invoices.transactions')->collect(); $customers = Contact::customer()->with('invoices.histories', 'invoices.totals', 'invoices.transactions', 'media')->collect();
return $this->response('sales.customers.index', compact('customers')); return $this->response('sales.customers.index', compact('customers'));
} }
@ -152,7 +152,7 @@ class Customers extends Controller
$response = $this->ajaxDispatch(new UpdateContact($customer, $request)); $response = $this->ajaxDispatch(new UpdateContact($customer, $request));
if ($response['success']) { if ($response['success']) {
$response['redirect'] = route('customers.index'); $response['redirect'] = route('customers.show', $response['data']->id);
$message = trans('messages.success.updated', ['type' => $customer->name]); $message = trans('messages.success.updated', ['type' => $customer->name]);

View File

@ -10,9 +10,9 @@ use App\Imports\Sales\Invoices as Import;
use App\Jobs\Document\CreateDocument; use App\Jobs\Document\CreateDocument;
use App\Jobs\Document\DeleteDocument; use App\Jobs\Document\DeleteDocument;
use App\Jobs\Document\DuplicateDocument; use App\Jobs\Document\DuplicateDocument;
use App\Jobs\Document\SendDocument;
use App\Jobs\Document\UpdateDocument; use App\Jobs\Document\UpdateDocument;
use App\Models\Document\Document; use App\Models\Document\Document;
use App\Notifications\Sale\Invoice as Notification;
use App\Traits\Documents; use App\Traits\Documents;
class Invoices extends Controller class Invoices extends Controller
@ -31,7 +31,7 @@ class Invoices extends Controller
*/ */
public function index() public function index()
{ {
$invoices = Document::invoice()->with('contact', 'transactions')->collect(['document_number'=> 'desc']); $invoices = Document::invoice()->with('contact', 'items', 'item_taxes', 'last_history', 'transactions', 'totals', 'histories', 'media')->collect(['document_number'=> 'desc']);
return $this->response('sales.invoices.index', compact('invoices')); return $this->response('sales.invoices.index', compact('invoices'));
} }
@ -260,12 +260,17 @@ class Invoices extends Controller
return redirect()->back(); return redirect()->back();
} }
// Notify the customer $response = $this->ajaxDispatch(new SendDocument($invoice));
$invoice->contact->notify(new Notification($invoice, 'invoice_new_customer', true));
event(new \App\Events\Document\DocumentSent($invoice)); if ($response['success']) {
$message = trans('documents.messages.email_sent', ['type' => trans_choice('general.invoices', 1)]);
flash(trans('documents.messages.email_sent', ['type' => trans_choice('general.invoices', 1)]))->success(); flash($message)->success();
} else {
$message = $response['message'];
flash($message)->error()->important();
}
return redirect()->back(); return redirect()->back();
} }

View File

@ -30,10 +30,10 @@ class Categories extends Controller
$query->withSubcategory(); $query->withSubcategory();
} }
$categories = $query->collect();
$types = $this->getCategoryTypes(); $types = $this->getCategoryTypes();
$categories = $query->type(array_keys($types))->collect();
return $this->response('settings.categories.index', compact('categories', 'types')); return $this->response('settings.categories.index', compact('categories', 'types'));
} }
@ -173,7 +173,9 @@ class Categories extends Controller
]; ];
}); });
return view('settings.categories.edit', compact('category', 'types', 'type_disabled', 'categories')); $parent_categories = $categories[$category->type] ?? [];
return view('settings.categories.edit', compact('category', 'types', 'type_disabled', 'categories', 'parent_categories'));
} }
/** /**

View File

@ -232,13 +232,13 @@ class Currencies extends Controller
$code = request('code'); $code = request('code');
$currencies = Currency::all()->pluck('rate', 'code');
if ($code) { if ($code) {
$currency = config('money.' . $code); $currencies = Currency::all()->pluck('rate', 'code');
$currency = config('money.currencies.' . $code);
$currency['rate'] = isset($currencies[$code]) ? $currencies[$code] : null; $currency['rate'] = isset($currencies[$code]) ? $currencies[$code] : null;
$currency['symbol_first'] = $currency['symbol_first'] ? 1 : 0; $currency['symbol_first'] = ! empty($currency['symbol_first']) ? 1 : 0;
$json = (object) $currency; $json = (object) $currency;
} }

View File

@ -3,6 +3,7 @@
namespace App\Http\Controllers\Settings; namespace App\Http\Controllers\Settings;
use App\Abstracts\Http\SettingController; use App\Abstracts\Http\SettingController;
use App\Models\Banking\Account;
use App\Models\Setting\Category; use App\Models\Setting\Category;
use App\Models\Setting\Tax; use App\Models\Setting\Tax;
@ -10,6 +11,8 @@ class Defaults extends SettingController
{ {
public function edit() public function edit()
{ {
$accounts = Account::enabled()->orderBy('name')->get()->pluck('title', 'id');
$sales_categories = Category::income()->enabled()->orderBy('name')->take(setting('default.select_limit'))->get(); $sales_categories = Category::income()->enabled()->orderBy('name')->take(setting('default.select_limit'))->get();
$sale_category_id = setting('default.income_category'); $sale_category_id = setting('default.income_category');
@ -37,6 +40,7 @@ class Defaults extends SettingController
$taxes = Tax::enabled()->orderBy('name')->get()->pluck('title', 'id'); $taxes = Tax::enabled()->orderBy('name')->get()->pluck('title', 'id');
return view('settings.default.edit', compact( return view('settings.default.edit', compact(
'accounts',
'sales_categories', 'sales_categories',
'purchases_categories', 'purchases_categories',
'taxes', 'taxes',

View File

@ -16,7 +16,7 @@ class Kernel extends HttpKernel
protected $middleware = [ protected $middleware = [
\App\Http\Middleware\TrustHosts::class, \App\Http\Middleware\TrustHosts::class,
\App\Http\Middleware\TrustProxies::class, \App\Http\Middleware\TrustProxies::class,
\Fruitcake\Cors\HandleCors::class, \Illuminate\Http\Middleware\HandleCors::class,
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class, \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class, \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class, \App\Http\Middleware\TrimStrings::class,
@ -141,13 +141,13 @@ class Kernel extends HttpKernel
]; ];
/** /**
* The application's route middleware. * The application's middleware aliases.
* *
* These middleware may be assigned to groups or used individually. * Aliases may be used to conveniently assign middleware to routes and groups.
* *
* @var array * @var array<string, class-string|string>
*/ */
protected $routeMiddleware = [ protected $middlewareAliases = [
// Laravel // Laravel
'auth' => \App\Http\Middleware\Authenticate::class, 'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,

View File

@ -26,11 +26,11 @@ class Browser extends Component
$this->status = false; $this->status = false;
} }
} elseif (Str::contains($user_agent, 'Edg')) { } elseif (Str::contains($user_agent, 'Edg')) {
// $view = 'livewire.notification.browser.chrome';
} elseif (Str::contains($user_agent, 'Safari')) {
// $view = 'livewire.notification.browser.edge'; // $view = 'livewire.notification.browser.edge';
} elseif (Str::contains($user_agent, 'Chrome')) { } elseif (Str::contains($user_agent, 'Safari')) {
// $view = 'livewire.notification.browser.safari'; // $view = 'livewire.notification.browser.safari';
} elseif (Str::contains($user_agent, 'Chrome')) {
// $view = 'livewire.notification.browser.chrome';
} elseif (Str::contains($user_agent, 'Opera')) { } elseif (Str::contains($user_agent, 'Opera')) {
// $view = 'livewire.notification.browser.opera'; // $view = 'livewire.notification.browser.opera';
} }

View File

@ -2,6 +2,7 @@
namespace App\Http\Middleware; namespace App\Http\Middleware;
use App\Events\Common\DatesFormating;
use Closure; use Closure;
use Date; use Date;
@ -10,14 +11,29 @@ class DateFormat
/** /**
* Handle an incoming request. * Handle an incoming request.
* *
* @param \Illuminate\Http\Request $request * @param \Illuminate\Http\Request $request
* @param \Closure $next * @param \Closure $next
*
* @return mixed * @return mixed
*/ */
public function handle($request, Closure $next) public function handle($request, Closure $next)
{ {
if (($request->method() == 'POST') || ($request->method() == 'PATCH')) { if (($request->method() == 'POST') || ($request->method() == 'PATCH')) {
$fields = ['paid_at', 'due_at', 'issued_at', 'started_at', 'ended_at', 'expire_at']; $columns = new \stdClass();
$columns->fields = [
'paid_at',
'due_at',
'issued_at',
'started_at',
'ended_at',
'expire_at',
'recurring_started_at',
'recurring_limit_date',
];
event(new DatesFormating($columns, $request));
$fields = $columns->fields;
foreach ($fields as $field) { foreach ($fields as $field) {
$date = $request->get($field); $date = $request->get($field);
@ -27,7 +43,7 @@ class DateFormat
} }
if (Date::parse($date)->format('H:i:s') == '00:00:00') { if (Date::parse($date)->format('H:i:s') == '00:00:00') {
$new_date = Date::parse($date)->format('Y-m-d') . ' ' . Date::now()->format('H:i:s'); $new_date = Date::parse($date)->format('Y-m-d') . ' ' . Date::now()->format('H:i:s');
} else { } else {
$new_date = Date::parse($date)->toDateTimeString(); $new_date = Date::parse($date)->toDateTimeString();
} }

View File

@ -84,7 +84,7 @@ class Money
$amount = $item['price']; $amount = $item['price'];
if (strpos($item['price'], config('money.' . $currency_code . '.symbol')) !== false) { if (strpos($item['price'], config('money.currencies.' . $currency_code . '.symbol')) !== false) {
$amount = $this->getAmount($item['price'], $currency_code); $amount = $this->getAmount($item['price'], $currency_code);
} }
@ -101,11 +101,11 @@ class Money
protected function getAmount($money_format, $currency_code) protected function getAmount($money_format, $currency_code)
{ {
try { try {
if (config('money.' . $currency_code . '.decimal_mark') !== '.') { if (config('money.currencies.' . $currency_code . '.decimal_mark') !== '.') {
$money_format = Str::replaceFirst('.', config('money.' . $currency_code . '.decimal_mark'), $money_format); $money_format = Str::replaceFirst('.', config('money.currencies.' . $currency_code . '.decimal_mark'), $money_format);
} }
$amount = money($money_format, $currency_code)->getAmount(); $amount = money($money_format, $currency_code, false)->getAmount();
} catch (InvalidArgumentException | OutOfBoundsException | UnexpectedValueException $e) { } catch (InvalidArgumentException | OutOfBoundsException | UnexpectedValueException $e) {
report($e); report($e);

View File

@ -0,0 +1,30 @@
<?php
namespace App\Http\Requests\Auth;
use Illuminate\Foundation\Http\FormRequest;
class Forgot extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'email' => 'required|email',
];
}
}

View File

@ -0,0 +1,32 @@
<?php
namespace App\Http\Requests\Auth;
use Illuminate\Foundation\Http\FormRequest;
class Reset extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'token' => 'required',
'email' => 'required|email',
'password' => 'required|confirmed|min:6',
];
}
}

View File

@ -29,7 +29,7 @@ class Transaction extends FormRequest
} }
// Get company id // Get company id
$company_id = (int) $this->request->get('company_id'); $company_id = (int) $this->request->get('company_id', company_id());
$attachment = 'nullable'; $attachment = 'nullable';
@ -37,7 +37,7 @@ class Transaction extends FormRequest
$attachment = 'mimes:' . config('filesystems.mimes') . '|between:0,' . config('filesystems.max_size') * 1024; $attachment = 'mimes:' . config('filesystems.mimes') . '|between:0,' . config('filesystems.max_size') * 1024;
} }
return [ $rules = [
'type' => 'required|string', 'type' => 'required|string',
'number' => 'required|string|unique:transactions,NULL,' . $id . ',id,company_id,' . $company_id . ',deleted_at,NULL', 'number' => 'required|string|unique:transactions,NULL,' . $id . ',id,company_id,' . $company_id . ',deleted_at,NULL',
'account_id' => 'required|integer', 'account_id' => 'required|integer',
@ -53,6 +53,29 @@ class Transaction extends FormRequest
'recurring_count' => 'gte:0', 'recurring_count' => 'gte:0',
'recurring_interval' => 'exclude_unless:recurring_frequency,custom|gt:0', 'recurring_interval' => 'exclude_unless:recurring_frequency,custom|gt:0',
]; ];
// Is Recurring
if ($this->request->has('recurring_frequency')) {
// first line of the recurring rule
if ($this->request->get('recurring_frequency') == 'custom') {
$rules['recurring_interval'] = 'required|gte:1';
$rules['recurring_custom_frequency'] = 'required|string|in:daily,weekly,monthly,yearly';
}
// second line of the recurring rule
$rules['recurring_started_at'] = 'required|date_format:Y-m-d H:i:s';
switch($this->request->get('recurring_limit')) {
case 'date':
$rules['recurring_limit_date'] = 'required|date_format:Y-m-d H:i:s|after_or_equal:recurring_started_at';
break;
case 'count':
$rules['recurring_limit_count'] = 'required|gte:0';
break;
}
}
return $rules;
} }
public function withValidator($validator) public function withValidator($validator)
@ -61,6 +84,18 @@ class Transaction extends FormRequest
$paid_at = Date::parse($this->request->get('paid_at'))->format('Y-m-d'); $paid_at = Date::parse($this->request->get('paid_at'))->format('Y-m-d');
$this->request->set('paid_at', $paid_at); $this->request->set('paid_at', $paid_at);
if ($this->request->get('recurring_started_at')) {
$recurring_started_at = Date::parse($this->request->get('recurring_started_at'))->format('Y-m-d');
$this->request->set('recurring_started_at', $recurring_started_at);
}
if ($this->request->get('recurring_limit_date')) {
$recurring_limit_date = Date::parse($this->request->get('recurring_limit_date'))->format('Y-m-d');
$this->request->set('recurring_limit_date', $recurring_limit_date);
}
} }
} }
} }

View File

@ -14,9 +14,10 @@ class CustomMail extends FormRequest
public function rules() public function rules()
{ {
return [ return [
'to' => 'required|email', 'to' => 'required|email',
'subject' => 'required|string', 'subject' => 'required|string',
'body' => 'required|string', 'body' => 'required|string',
'attachments.*' => 'nullable|boolean',
]; ];
} }
} }

View File

@ -31,7 +31,7 @@ class Item extends FormRequest
} }
return [ return [
'type' => 'required|string', 'type' => 'required|string|in:product,service',
'name' => 'required|string', 'name' => 'required|string',
'sale_price' => $sale_price . '|regex:/^(?=.*?[0-9])[0-9.,]+$/', 'sale_price' => $sale_price . '|regex:/^(?=.*?[0-9])[0-9.,]+$/',
'purchase_price' => $purchase_price . '|regex:/^(?=.*?[0-9])[0-9.,]+$/', 'purchase_price' => $purchase_price . '|regex:/^(?=.*?[0-9])[0-9.,]+$/',

View File

@ -48,6 +48,7 @@ class Document extends FormRequest
$rules = [ $rules = [
'type' => 'required|string', 'type' => 'required|string',
'document_number' => 'required|string|unique:documents,NULL,' . $id . ',id,type,' . $type . ',company_id,' . $company_id . ',deleted_at,NULL', 'document_number' => 'required|string|unique:documents,NULL,' . $id . ',id,type,' . $type . ',company_id,' . $company_id . ',deleted_at,NULL',
//'status' => 'required|string|in:draft,paid,partial,sent,received,viewed,cancelled',
'status' => 'required|string', 'status' => 'required|string',
'issued_at' => 'required|date_format:Y-m-d H:i:s|before_or_equal:due_at', 'issued_at' => 'required|date_format:Y-m-d H:i:s|before_or_equal:due_at',
'due_at' => 'required|date_format:Y-m-d H:i:s|after_or_equal:issued_at', 'due_at' => 'required|date_format:Y-m-d H:i:s|after_or_equal:issued_at',
@ -65,6 +66,27 @@ class Document extends FormRequest
'recurring_interval' => 'exclude_unless:recurring_frequency,custom|gt:0', 'recurring_interval' => 'exclude_unless:recurring_frequency,custom|gt:0',
]; ];
// Is Recurring
if ($this->request->has('recurring_frequency')) {
// first line of the recurring rule
if ($this->request->get('recurring_frequency') == 'custom') {
$rules['recurring_interval'] = 'required|gte:1';
$rules['recurring_custom_frequency'] = 'required|string|in:daily,weekly,monthly,yearly';
}
// second line of the recurring rule
$rules['recurring_started_at'] = 'required|date_format:Y-m-d H:i:s';
switch($this->request->get('recurring_limit')) {
case 'date':
$rules['recurring_limit_date'] = 'required|date_format:Y-m-d H:i:s|after_or_equal:recurring_started_at';
break;
case 'count':
$rules['recurring_limit_count'] = 'required|gte:0';
break;
}
}
$items = $this->request->all('items'); $items = $this->request->all('items');
if ($items) { if ($items) {
@ -93,6 +115,18 @@ class Document extends FormRequest
$this->request->set('issued_at', $issued_at); $this->request->set('issued_at', $issued_at);
$this->request->set('due_at', $due_at); $this->request->set('due_at', $due_at);
if ($this->request->has('recurring_started_at')) {
$recurring_started_at = Date::parse($this->request->get('recurring_started_at'))->format('Y-m-d');
$this->request->set('recurring_started_at', $recurring_started_at);
}
if ($this->request->has('recurring_limit_date')) {
$recurring_limit_date = Date::parse($this->request->get('recurring_limit_date'))->format('Y-m-d');
$this->request->set('recurring_limit_date', $recurring_limit_date);
}
} }
} }

View File

@ -13,9 +13,11 @@ class Category extends FormRequest
*/ */
public function rules() public function rules()
{ {
$types = collect(config('type.category'))->keys();
return [ return [
'name' => 'required|string', 'name' => 'required|string',
'type' => 'required|string', 'type' => 'required|string|in:' . $types->implode(','),
'color' => 'required|string', 'color' => 'required|string',
]; ];
} }

View File

@ -45,6 +45,10 @@ class Setting extends FormRequest
$rules['number_digit'] = 'required|integer|min:1|max:20'; $rules['number_digit'] = 'required|integer|min:1|max:20';
} }
if ($this->request->has('number_next')) {
$rules['number_next'] = 'required|integer';
}
return $rules; return $rules;
} }

View File

@ -22,9 +22,9 @@ class Tax extends FormRequest
$enabled = 'nullable'; $enabled = 'nullable';
} }
$company_id = (int) $this->request->get('company_id'); $company_id = (int) $this->request->get('company_id', company_id());
$type = 'required|string'; $type = 'required|string|in:fixed,normal,inclusive,withholding,compound';
if (!empty($this->request->get('type')) && $this->request->get('type') == 'compound') { if (!empty($this->request->get('type')) && $this->request->get('type') == 'compound') {
$type .= '|unique:taxes,NULL,' . $id . ',id,company_id,' . $company_id . ',type,compound,deleted_at,NULL'; $type .= '|unique:taxes,NULL,' . $id . ',id,company_id,' . $company_id . ',type,compound,deleted_at,NULL';
@ -32,7 +32,7 @@ class Tax extends FormRequest
return [ return [
'name' => 'required|string', 'name' => 'required|string',
'rate' => 'required|min:0|max:100', 'rate' => 'required|numeric|min:0|max:100',
'type' => $type, 'type' => $type,
'enabled' => $enabled, 'enabled' => $enabled,
]; ];

View File

@ -22,9 +22,9 @@ class Account extends JsonResource
'number' => $this->number, 'number' => $this->number,
'currency_code' => $this->currency_code, 'currency_code' => $this->currency_code,
'opening_balance' => $this->opening_balance, 'opening_balance' => $this->opening_balance,
'opening_balance_formatted' => money($this->opening_balance, $this->currency_code, true)->format(), 'opening_balance_formatted' => money($this->opening_balance, $this->currency_code)->format(),
'current_balance' => $this->balance, 'current_balance' => $this->balance,
'current_balance_formatted' => money($this->balance, $this->currency_code, true)->format(), 'current_balance_formatted' => money($this->balance, $this->currency_code)->format(),
'bank_name' => $this->bank_name, 'bank_name' => $this->bank_name,
'bank_phone' => $this->bank_phone, 'bank_phone' => $this->bank_phone,
'bank_address' => $this->bank_address, 'bank_address' => $this->bank_address,

View File

@ -22,7 +22,7 @@ class Reconciliation extends JsonResource
'started_at' => $this->started_at->toIso8601String(), 'started_at' => $this->started_at->toIso8601String(),
'ended_at' => $this->ended_at->toIso8601String(), 'ended_at' => $this->ended_at->toIso8601String(),
'closing_balance' => $this->closing_balance, 'closing_balance' => $this->closing_balance,
'closing_balance_formatted' => money($this->closing_balance, default_currency(), true)->format(), 'closing_balance_formatted' => money($this->closing_balance)->format(),
'reconciled' => $this->reconciled, 'reconciled' => $this->reconciled,
'created_from' => $this->created_from, 'created_from' => $this->created_from,
'created_by' => $this->created_by, 'created_by' => $this->created_by,

View File

@ -25,7 +25,7 @@ class Transaction extends JsonResource
'account_id' => $this->account_id, 'account_id' => $this->account_id,
'paid_at' => $this->paid_at->toIso8601String(), 'paid_at' => $this->paid_at->toIso8601String(),
'amount' => $this->amount, 'amount' => $this->amount,
'amount_formatted' => money($this->amount, $this->currency_code, true)->format(), 'amount_formatted' => money($this->amount, $this->currency_code)->format(),
'currency_code' => $this->currency_code, 'currency_code' => $this->currency_code,
'currency_rate' => $this->currency_rate, 'currency_rate' => $this->currency_rate,
'document_id' => $this->document_id, 'document_id' => $this->document_id,

View File

@ -25,7 +25,7 @@ class Transfer extends JsonResource
'to_account' => $income_transaction->account->name, 'to_account' => $income_transaction->account->name,
'to_account_id' => $income_transaction->account->id, 'to_account_id' => $income_transaction->account->id,
'amount' => $expense_transaction->amount, 'amount' => $expense_transaction->amount,
'amount_formatted' => money($expense_transaction->amount, $expense_transaction->currency_code, true)->format(), 'amount_formatted' => money($expense_transaction->amount, $expense_transaction->currency_code)->format(),
'currency_code' => $expense_transaction->currency_code, 'currency_code' => $expense_transaction->currency_code,
'paid_at' => $expense_transaction->paid_at ? $expense_transaction->paid_at->toIso8601String() : '', 'paid_at' => $expense_transaction->paid_at ? $expense_transaction->paid_at->toIso8601String() : '',
'created_from' => $this->created_from, 'created_from' => $this->created_from,

View File

@ -23,9 +23,9 @@ class Item extends JsonResource
'name' => $this->name, 'name' => $this->name,
'description' => $this->description, 'description' => $this->description,
'sale_price' => $this->sale_price, 'sale_price' => $this->sale_price,
'sale_price_formatted' => money($this->sale_price, default_currency(), true)->format(), 'sale_price_formatted' => money((double) $this->sale_price)->format(),
'purchase_price' => $this->purchase_price, 'purchase_price' => $this->purchase_price,
'purchase_price_formatted' => money($this->purchase_price, default_currency(), true)->format(), 'purchase_price_formatted' => money((double) $this->purchase_price)->format(),
'category_id' => $this->category_id, 'category_id' => $this->category_id,
'picture' => $this->picture, 'picture' => $this->picture,
'enabled' => $this->enabled, 'enabled' => $this->enabled,

View File

@ -8,6 +8,7 @@ use App\Http\Resources\Document\DocumentHistory;
use App\Http\Resources\Document\DocumentItem; use App\Http\Resources\Document\DocumentItem;
use App\Http\Resources\Document\DocumentItemTax; use App\Http\Resources\Document\DocumentItemTax;
use App\Http\Resources\Document\DocumentTotal; use App\Http\Resources\Document\DocumentTotal;
use App\Http\Resources\Setting\Category;
use App\Http\Resources\Setting\Currency; use App\Http\Resources\Setting\Currency;
use Illuminate\Http\Resources\Json\JsonResource; use Illuminate\Http\Resources\Json\JsonResource;
@ -31,7 +32,8 @@ class Document extends JsonResource
'issued_at' => $this->issued_at ? $this->issued_at->toIso8601String() : '', 'issued_at' => $this->issued_at ? $this->issued_at->toIso8601String() : '',
'due_at' => $this->due_at ? $this->due_at->toIso8601String() : '', 'due_at' => $this->due_at ? $this->due_at->toIso8601String() : '',
'amount' => $this->amount, 'amount' => $this->amount,
'amount_formatted' => money($this->amount, $this->currency_code, true)->format(), 'amount_formatted' => money($this->amount, $this->currency_code)->format(),
'category_id' => $this->category_id,
'currency_code' => $this->currency_code, 'currency_code' => $this->currency_code,
'currency_rate' => $this->currency_rate, 'currency_rate' => $this->currency_rate,
'contact_id' => $this->contact_id, 'contact_id' => $this->contact_id,
@ -50,6 +52,7 @@ class Document extends JsonResource
'created_by' => $this->created_by, 'created_by' => $this->created_by,
'created_at' => $this->created_at ? $this->created_at->toIso8601String() : '', 'created_at' => $this->created_at ? $this->created_at->toIso8601String() : '',
'updated_at' => $this->updated_at ? $this->updated_at->toIso8601String() : '', 'updated_at' => $this->updated_at ? $this->updated_at->toIso8601String() : '',
'category' => new Category($this->category),
'currency' => new Currency($this->currency), 'currency' => new Currency($this->currency),
'contact' => new Contact($this->contact), 'contact' => new Contact($this->contact),
'histories' => [static::$wrap => DocumentHistory::collection($this->histories)], 'histories' => [static::$wrap => DocumentHistory::collection($this->histories)],

View File

@ -22,10 +22,11 @@ class DocumentItem extends JsonResource
'document_id' => $this->document_id, 'document_id' => $this->document_id,
'item_id' => $this->item_id, 'item_id' => $this->item_id,
'name' => $this->name, 'name' => $this->name,
'description' => $this->description,
'price' => $this->price, 'price' => $this->price,
'price_formatted' => money($this->price, $this->document->currency_code, true)->format(), 'price_formatted' => money($this->price, $this->document->currency_code)->format(),
'total' => $this->total, 'total' => $this->total,
'total_formatted' => money($this->total, $this->document->currency_code, true)->format(), 'total_formatted' => money($this->total, $this->document->currency_code)->format(),
'created_from' => $this->created_from, 'created_from' => $this->created_from,
'created_by' => $this->created_by, 'created_by' => $this->created_by,
'created_at' => $this->created_at ? $this->created_at->toIso8601String() : '', 'created_at' => $this->created_at ? $this->created_at->toIso8601String() : '',

View File

@ -24,7 +24,7 @@ class DocumentItemTax extends JsonResource
'tax_id' => $this->tax_id, 'tax_id' => $this->tax_id,
'name' => $this->name, 'name' => $this->name,
'amount' => $this->amount, 'amount' => $this->amount,
'amount_formatted' => money($this->amount, $this->document->currency_code, true)->format(), 'amount_formatted' => money($this->amount, $this->document->currency_code)->format(),
'created_from' => $this->created_from, 'created_from' => $this->created_from,
'created_by' => $this->created_by, 'created_by' => $this->created_by,
'created_at' => $this->created_at ? $this->created_at->toIso8601String() : '', 'created_at' => $this->created_at ? $this->created_at->toIso8601String() : '',

View File

@ -22,7 +22,7 @@ class DocumentTotal extends JsonResource
'code' => $this->code, 'code' => $this->code,
'name' => $this->name, 'name' => $this->name,
'amount' => $this->amount, 'amount' => $this->amount,
'amount_formatted' => money($this->amount, $this->document->currency_code, true)->format(), 'amount_formatted' => money($this->amount, $this->document->currency_code)->format(),
'sort_order' => $this->sort_order, 'sort_order' => $this->sort_order,
'created_from' => $this->created_from, 'created_from' => $this->created_from,
'created_by' => $this->created_by, 'created_by' => $this->created_by,

View File

@ -8,6 +8,8 @@ use App\Models\Banking\Transaction as Model;
class Transactions extends Import class Transactions extends Import
{ {
public $request_class = Request::class;
public function model(array $row) public function model(array $row)
{ {
return new Model($row); return new Model($row);
@ -17,17 +19,12 @@ class Transactions extends Import
{ {
$row = parent::map($row); $row = parent::map($row);
$row['currency_code'] = $this->getCurrencyCode($row);
$row['account_id'] = $this->getAccountId($row); $row['account_id'] = $this->getAccountId($row);
$row['category_id'] = $this->getCategoryId($row); $row['category_id'] = $this->getCategoryId($row);
$row['contact_id'] = $this->getContactId($row); $row['contact_id'] = $this->getContactId($row);
$row['currency_code'] = $this->getCurrencyCode($row);
$row['document_id'] = $this->getDocumentId($row); $row['document_id'] = $this->getDocumentId($row);
return $row; return $row;
} }
public function rules(): array
{
return (new Request())->rules();
}
} }

View File

@ -26,10 +26,10 @@ class Transfers extends Import
$row = parent::map($row); $row = parent::map($row);
$row['transferred_at'] = Date::parse($row['transferred_at'])->format('Y-m-d'); $row['transferred_at'] = Date::parse($row['transferred_at'])->format('Y-m-d');
$row['from_account_id'] = $this->getFromAccountId($row);
$row['to_account_id'] = $this->getToAccountId($row);
$row['from_currency_code'] = $this->getFromCurrencyCode($row); $row['from_currency_code'] = $this->getFromCurrencyCode($row);
$row['to_currency_code'] = $this->getToCurrencyCode($row); $row['to_currency_code'] = $this->getToCurrencyCode($row);
$row['from_account_id'] = $this->getFromAccountId($row);
$row['to_account_id'] = $this->getToAccountId($row);
$row['expense_transaction_id'] = $this->getExpenseTransactionId($row); $row['expense_transaction_id'] = $this->getExpenseTransactionId($row);
$row['income_transaction_id'] = $this->getIncomeTransactionId($row); $row['income_transaction_id'] = $this->getIncomeTransactionId($row);
@ -41,10 +41,10 @@ class Transfers extends Import
return [ return [
'from_account_id' => 'required|integer', 'from_account_id' => 'required|integer',
'from_currency_code' => 'required|string|currency', 'from_currency_code' => 'required|string|currency',
'from_currency_rate' => 'required', 'from_currency_rate' => 'required|gt:0',
'to_account_id' => 'required|integer', 'to_account_id' => 'required|integer',
'to_currency_code' => 'required|string|currency', 'to_currency_code' => 'required|string|currency',
'to_currency_rate' => 'required', 'to_currency_rate' => 'required|gt:0',
'amount' => 'required|amount', 'amount' => 'required|amount',
'transferred_at' => 'required|date_format:Y-m-d', 'transferred_at' => 'required|date_format:Y-m-d',
'payment_method' => 'required|string', 'payment_method' => 'required|string',

View File

@ -4,11 +4,12 @@ namespace App\Imports\Common\Sheets;
use App\Abstracts\Import; use App\Abstracts\Import;
use App\Http\Requests\Common\ItemTax as Request; use App\Http\Requests\Common\ItemTax as Request;
use App\Models\Common\Item;
use App\Models\Common\ItemTax as Model; use App\Models\Common\ItemTax as Model;
class ItemTaxes extends Import class ItemTaxes extends Import
{ {
public $request_class = Request::class;
public function model(array $row) public function model(array $row)
{ {
return new Model($row); return new Model($row);
@ -16,21 +17,16 @@ class ItemTaxes extends Import
public function map($row): array public function map($row): array
{ {
$row = parent::map($row); if ($this->isEmpty($row, 'item_name')) {
$row['item_id'] = (int) Item::where('name', $row['item_name'])->value('id');
if ($this->isEmpty($row, 'item_id')) {
return []; return [];
} }
$row = parent::map($row);
$row['item_id'] = $this->getItemId($row);
$row['tax_id'] = $this->getTaxId($row); $row['tax_id'] = $this->getTaxId($row);
return $row; return $row;
} }
public function rules(): array
{
return (new Request())->rules();
}
} }

View File

@ -8,6 +8,8 @@ use App\Models\Common\Item as Model;
class Items extends Import class Items extends Import
{ {
public $request_class = Request::class;
public function model(array $row) public function model(array $row)
{ {
return new Model($row); return new Model($row);
@ -25,9 +27,4 @@ class Items extends Import
return $row; return $row;
} }
public function rules(): array
{
return (new Request())->rules();
}
} }

View File

@ -9,6 +9,8 @@ use App\Models\Document\DocumentHistory as Model;
class BillHistories extends Import class BillHistories extends Import
{ {
public $request_class = Request::class;
public function model(array $row) public function model(array $row)
{ {
return new Model($row); return new Model($row);
@ -20,6 +22,8 @@ class BillHistories extends Import
return []; return [];
} }
$row['bill_number'] = (string) $row['bill_number'];
$row = parent::map($row); $row = parent::map($row);
$row['document_id'] = (int) Document::bill()->number($row['bill_number'])->pluck('id')->first(); $row['document_id'] = (int) Document::bill()->number($row['bill_number'])->pluck('id')->first();
@ -31,10 +35,8 @@ class BillHistories extends Import
return $row; return $row;
} }
public function rules(): array public function prepareRules(array $rules): array
{ {
$rules = (new Request())->rules();
$rules['bill_number'] = 'required|string'; $rules['bill_number'] = 'required|string';
unset($rules['bill_id']); unset($rules['bill_id']);

View File

@ -11,6 +11,8 @@ use App\Models\Document\DocumentItemTax as Model;
class BillItemTaxes extends Import class BillItemTaxes extends Import
{ {
public $request_class = Request::class;
public function model(array $row) public function model(array $row)
{ {
return new Model($row); return new Model($row);
@ -22,6 +24,8 @@ class BillItemTaxes extends Import
return []; return [];
} }
$row['bill_number'] = (string) $row['bill_number'];
$row = parent::map($row); $row = parent::map($row);
$row['document_id'] = (int) Document::bill()->number($row['bill_number'])->pluck('id')->first(); $row['document_id'] = (int) Document::bill()->number($row['bill_number'])->pluck('id')->first();
@ -44,10 +48,8 @@ class BillItemTaxes extends Import
return $row; return $row;
} }
public function rules(): array public function prepareRules(array $rules): array
{ {
$rules = (new Request())->rules();
$rules['bill_number'] = 'required|string'; $rules['bill_number'] = 'required|string';
unset($rules['bill_id']); unset($rules['bill_id']);

View File

@ -9,6 +9,8 @@ use App\Models\Document\DocumentItem as Model;
class BillItems extends Import class BillItems extends Import
{ {
public $request_class = Request::class;
public function model(array $row) public function model(array $row)
{ {
return new Model($row); return new Model($row);
@ -20,6 +22,8 @@ class BillItems extends Import
return []; return [];
} }
$row['bill_number'] = (string) $row['bill_number'];
$row = parent::map($row); $row = parent::map($row);
$row['document_id'] = (int) Document::bill()->number($row['bill_number'])->pluck('id')->first(); $row['document_id'] = (int) Document::bill()->number($row['bill_number'])->pluck('id')->first();
@ -30,6 +34,8 @@ class BillItems extends Import
$row['name'] = $row['item_name']; $row['name'] = $row['item_name'];
} }
$row['description'] = !empty($row['item_description']) ? $row['item_description'] : '';
$row['tax'] = (double) $row['tax']; $row['tax'] = (double) $row['tax'];
$row['tax_id'] = 0; $row['tax_id'] = 0;
$row['type'] = Document::BILL_TYPE; $row['type'] = Document::BILL_TYPE;
@ -37,10 +43,8 @@ class BillItems extends Import
return $row; return $row;
} }
public function rules(): array public function prepareRules(array $rules): array
{ {
$rules = (new Request())->rules();
$rules['bill_number'] = 'required|string'; $rules['bill_number'] = 'required|string';
unset($rules['bill_id']); unset($rules['bill_id']);

View File

@ -9,6 +9,8 @@ use App\Models\Document\DocumentTotal as Model;
class BillTotals extends Import class BillTotals extends Import
{ {
public $request_class = Request::class;
public function model(array $row) public function model(array $row)
{ {
return new Model($row); return new Model($row);
@ -20,6 +22,8 @@ class BillTotals extends Import
return []; return [];
} }
$row['bill_number'] = (string) $row['bill_number'];
$row = parent::map($row); $row = parent::map($row);
$row['document_id'] = (int) Document::bill()->number($row['bill_number'])->pluck('id')->first(); $row['document_id'] = (int) Document::bill()->number($row['bill_number'])->pluck('id')->first();
@ -28,10 +32,8 @@ class BillTotals extends Import
return $row; return $row;
} }
public function rules(): array public function prepareRules(array $rules): array
{ {
$rules = (new Request())->rules();
$rules['bill_number'] = 'required|string'; $rules['bill_number'] = 'required|string';
unset($rules['bill_id']); unset($rules['bill_id']);

View File

@ -8,6 +8,8 @@ use App\Models\Banking\Transaction as Model;
class BillTransactions extends Import class BillTransactions extends Import
{ {
public $request_class = Request::class;
public function model(array $row) public function model(array $row)
{ {
return new Model($row); return new Model($row);
@ -19,6 +21,8 @@ class BillTransactions extends Import
return []; return [];
} }
$row['bill_number'] = (string) $row['bill_number'];
$row = parent::map($row); $row = parent::map($row);
$row['type'] = 'expense'; $row['type'] = 'expense';
@ -32,10 +36,8 @@ class BillTransactions extends Import
return $row; return $row;
} }
public function rules(): array public function prepareRules(array $rules): array
{ {
$rules = (new Request())->rules();
$rules['bill_number'] = 'required|string'; $rules['bill_number'] = 'required|string';
return $rules; return $rules;

View File

@ -9,6 +9,8 @@ use Illuminate\Support\Str;
class Bills extends Import class Bills extends Import
{ {
public $request_class = Request::class;
public function model(array $row) public function model(array $row)
{ {
return new Model($row); return new Model($row);
@ -20,6 +22,8 @@ class Bills extends Import
return []; return [];
} }
$row['bill_number'] = (string) $row['bill_number'];
$row = parent::map($row); $row = parent::map($row);
$country = array_search($row['contact_country'], trans('countries')); $country = array_search($row['contact_country'], trans('countries'));
@ -35,16 +39,14 @@ class Bills extends Import
return $row; return $row;
} }
public function rules(): array public function prepareRules(array $rules): array
{ {
$rules = (new Request())->rules();
$rules['bill_number'] = Str::replaceFirst('unique:documents,NULL', 'unique:documents,document_number', $rules['document_number']); $rules['bill_number'] = Str::replaceFirst('unique:documents,NULL', 'unique:documents,document_number', $rules['document_number']);
$rules['billed_at'] = $rules['issued_at']; $rules['billed_at'] = $rules['issued_at'];
$rules['currency_rate'] = 'required'; $rules['currency_rate'] = 'required|gt:0';
unset($rules['document_number'], $rules['issued_at'], $rules['type']); unset($rules['document_number'], $rules['issued_at'], $rules['type']);
return $this->replaceForBatchRules($rules); return $rules;
} }
} }

View File

@ -8,6 +8,8 @@ use App\Models\Common\Contact as Model;
class Vendors extends Import class Vendors extends Import
{ {
public $request_class = Request::class;
public function model(array $row) public function model(array $row)
{ {
return new Model($row); return new Model($row);
@ -26,9 +28,4 @@ class Vendors extends Import
return $row; return $row;
} }
public function rules(): array
{
return (new Request())->rules();
}
} }

View File

@ -3,11 +3,14 @@
namespace App\Imports\Sales; namespace App\Imports\Sales;
use App\Abstracts\Import; use App\Abstracts\Import;
use App\Models\Auth\User;
use App\Http\Requests\Common\Contact as Request; use App\Http\Requests\Common\Contact as Request;
use App\Models\Common\Contact as Model; use App\Models\Common\Contact as Model;
class Customers extends Import class Customers extends Import
{ {
public $request_class = Request::class;
public function model(array $row) public function model(array $row)
{ {
return new Model($row); return new Model($row);
@ -24,11 +27,10 @@ class Customers extends Import
$row['currency_code'] = $this->getCurrencyCode($row); $row['currency_code'] = $this->getCurrencyCode($row);
$row['user_id'] = null; $row['user_id'] = null;
if (isset($row['can_login']) && isset($row['email'])) {
$row['user_id'] = User::where('email', $row['email'])->first()?->id ?? null;
}
return $row; return $row;
} }
public function rules(): array
{
return (new Request())->rules();
}
} }

View File

@ -9,6 +9,8 @@ use App\Models\Document\DocumentHistory as Model;
class InvoiceHistories extends Import class InvoiceHistories extends Import
{ {
public $request_class = Request::class;
public function model(array $row) public function model(array $row)
{ {
return new Model($row); return new Model($row);
@ -20,6 +22,8 @@ class InvoiceHistories extends Import
return []; return [];
} }
$row['invoice_number'] = (string) $row['invoice_number'];
$row = parent::map($row); $row = parent::map($row);
$row['document_id'] = (int) Document::invoice()->number($row['invoice_number'])->pluck('id')->first(); $row['document_id'] = (int) Document::invoice()->number($row['invoice_number'])->pluck('id')->first();
@ -31,10 +35,8 @@ class InvoiceHistories extends Import
return $row; return $row;
} }
public function rules(): array public function prepareRules(array $rules): array
{ {
$rules = (new Request())->rules();
$rules['invoice_number'] = 'required|string'; $rules['invoice_number'] = 'required|string';
unset($rules['invoice_id']); unset($rules['invoice_id']);

View File

@ -11,6 +11,8 @@ use App\Models\Document\DocumentItemTax as Model;
class InvoiceItemTaxes extends Import class InvoiceItemTaxes extends Import
{ {
public $request_class = Request::class;
public function model(array $row) public function model(array $row)
{ {
return new Model($row); return new Model($row);
@ -22,6 +24,8 @@ class InvoiceItemTaxes extends Import
return []; return [];
} }
$row['invoice_number'] = (string) $row['invoice_number'];
$row = parent::map($row); $row = parent::map($row);
$row['document_id'] = (int) Document::invoice()->number($row['invoice_number'])->pluck('id')->first(); $row['document_id'] = (int) Document::invoice()->number($row['invoice_number'])->pluck('id')->first();
@ -44,10 +48,8 @@ class InvoiceItemTaxes extends Import
return $row; return $row;
} }
public function rules(): array public function prepareRules(array $rules): array
{ {
$rules = (new Request())->rules();
$rules['invoice_number'] = 'required|string'; $rules['invoice_number'] = 'required|string';
unset($rules['invoice_id']); unset($rules['invoice_id']);

View File

@ -9,6 +9,8 @@ use App\Models\Document\DocumentItem as Model;
class InvoiceItems extends Import class InvoiceItems extends Import
{ {
public $request_class = Request::class;
public function model(array $row) public function model(array $row)
{ {
return new Model($row); return new Model($row);
@ -20,16 +22,20 @@ class InvoiceItems extends Import
return []; return [];
} }
$row['invoice_number'] = (string) $row['invoice_number'];
$row = parent::map($row); $row = parent::map($row);
$row['document_id'] = (int) Document::invoice()->number($row['invoice_number'])->pluck('id')->first(); $row['document_id'] = (int) Document::invoice()->number($row['invoice_number'])->pluck('id')->first();
if (empty($row['item_id']) && !empty($row['item_name'])) { if (empty($row['item_id']) && ! empty($row['item_name'])) {
$row['item_id'] = $this->getItemIdFromName($row); $row['item_id'] = $this->getItemIdFromName($row);
$row['name'] = $row['item_name']; $row['name'] = $row['item_name'];
} }
$row['description'] = !empty($row['item_description']) ? $row['item_description'] : '';
$row['tax'] = (double) $row['tax']; $row['tax'] = (double) $row['tax'];
$row['tax_id'] = 0; $row['tax_id'] = 0;
$row['type'] = Document::INVOICE_TYPE; $row['type'] = Document::INVOICE_TYPE;
@ -37,10 +43,8 @@ class InvoiceItems extends Import
return $row; return $row;
} }
public function rules(): array public function prepareRules(array $rules): array
{ {
$rules = (new Request())->rules();
$rules['invoice_number'] = 'required|string'; $rules['invoice_number'] = 'required|string';
unset($rules['invoice_id']); unset($rules['invoice_id']);

View File

@ -9,6 +9,8 @@ use App\Models\Document\DocumentTotal as Model;
class InvoiceTotals extends Import class InvoiceTotals extends Import
{ {
public $request_class = Request::class;
public function model(array $row) public function model(array $row)
{ {
return new Model($row); return new Model($row);
@ -20,6 +22,8 @@ class InvoiceTotals extends Import
return []; return [];
} }
$row['invoice_number'] = (string) $row['invoice_number'];
$row = parent::map($row); $row = parent::map($row);
$row['document_id'] = (int) Document::invoice()->number($row['invoice_number'])->pluck('id')->first(); $row['document_id'] = (int) Document::invoice()->number($row['invoice_number'])->pluck('id')->first();
@ -28,10 +32,8 @@ class InvoiceTotals extends Import
return $row; return $row;
} }
public function rules(): array public function prepareRules(array $rules): array
{ {
$rules = (new Request())->rules();
$rules['invoice_number'] = 'required|string'; $rules['invoice_number'] = 'required|string';
unset($rules['invoice_id']); unset($rules['invoice_id']);

View File

@ -8,6 +8,8 @@ use App\Models\Banking\Transaction as Model;
class InvoiceTransactions extends Import class InvoiceTransactions extends Import
{ {
public $request_class = Request::class;
public function model(array $row) public function model(array $row)
{ {
return new Model($row); return new Model($row);
@ -19,23 +21,23 @@ class InvoiceTransactions extends Import
return []; return [];
} }
$row['invoice_number'] = (string) $row['invoice_number'];
$row = parent::map($row); $row = parent::map($row);
$row['type'] = 'income'; $row['type'] = 'income';
$row['currency_code'] = $this->getCurrencyCode($row);
$row['account_id'] = $this->getAccountId($row); $row['account_id'] = $this->getAccountId($row);
$row['category_id'] = $this->getCategoryId($row, 'income'); $row['category_id'] = $this->getCategoryId($row, 'income');
$row['contact_id'] = $this->getContactId($row, 'customer'); $row['contact_id'] = $this->getContactId($row, 'customer');
$row['currency_code'] = $this->getCurrencyCode($row);
$row['document_id'] = $this->getDocumentId($row); $row['document_id'] = $this->getDocumentId($row);
$row['number'] = $row['transaction_number']; $row['number'] = $row['transaction_number'];
return $row; return $row;
} }
public function rules(): array public function prepareRules(array $rules): array
{ {
$rules = (new Request())->rules();
$rules['invoice_number'] = 'required|string'; $rules['invoice_number'] = 'required|string';
return $rules; return $rules;

View File

@ -9,6 +9,8 @@ use Illuminate\Support\Str;
class Invoices extends Import class Invoices extends Import
{ {
public $request_class = Request::class;
public function model(array $row) public function model(array $row)
{ {
return new Model($row); return new Model($row);
@ -20,6 +22,8 @@ class Invoices extends Import
return []; return [];
} }
$row['invoice_number'] = (string) $row['invoice_number'];
$row = parent::map($row); $row = parent::map($row);
$country = array_search($row['contact_country'], trans('countries')); $country = array_search($row['contact_country'], trans('countries'));
@ -35,16 +39,14 @@ class Invoices extends Import
return $row; return $row;
} }
public function rules(): array public function prepareRules(array $rules): array
{ {
$rules = (new Request())->rules();
$rules['invoice_number'] = Str::replaceFirst('unique:documents,NULL', 'unique:documents,document_number', $rules['document_number']); $rules['invoice_number'] = Str::replaceFirst('unique:documents,NULL', 'unique:documents,document_number', $rules['document_number']);
$rules['invoiced_at'] = $rules['issued_at']; $rules['invoiced_at'] = $rules['issued_at'];
$rules['currency_rate'] = 'required'; $rules['currency_rate'] = 'required|gt:0';
unset($rules['document_number'], $rules['issued_at'], $rules['type']); unset($rules['document_number'], $rules['issued_at'], $rules['type']);
return $this->replaceForBatchRules($rules); return $rules;
} }
} }

View File

@ -8,6 +8,8 @@ use App\Models\Setting\Category as Model;
class Categories extends Import class Categories extends Import
{ {
public $request_class = Request::class;
public function model(array $row) public function model(array $row)
{ {
return new Model($row); return new Model($row);
@ -21,9 +23,4 @@ class Categories extends Import
return $row; return $row;
} }
public function rules(): array
{
return (new Request())->rules();
}
} }

View File

@ -8,13 +8,10 @@ use App\Models\Setting\Tax as Model;
class Taxes extends Import class Taxes extends Import
{ {
public $request_class = Request::class;
public function model(array $row) public function model(array $row)
{ {
return new Model($row); return new Model($row);
} }
public function rules(): array
{
return (new Request())->rules();
}
} }

View File

@ -0,0 +1,12 @@
<?php
namespace App\Interfaces\Utility;
use App\Models\Common\Contact;
interface DocumentNumber
{
public function getNextNumber(string $type, ?Contact $contact): string;
public function increaseNextNumber(string $type, ?Contact $contact): void;
}

View File

@ -0,0 +1,12 @@
<?php
namespace App\Interfaces\Utility;
use App\Models\Common\Contact;
interface TransactionNumber
{
public function getNextNumber(string $type, string $suffix, ?Contact $contact): string;
public function increaseNextNumber(string $type, string $suffix, ?Contact $contact): void;
}

Some files were not shown because too many files have changed in this diff Show More