diff --git a/.env.example b/.env.example index 19c98183f300..ab3a104fb6f4 100644 --- a/.env.example +++ b/.env.example @@ -26,7 +26,7 @@ BROADCAST_DRIVER=log LOG_CHANNEL=stack CACHE_DRIVER=file QUEUE_CONNECTION=database -SESSION_DRIVER=cookie +SESSION_DRIVER=file SESSION_LIFETIME=120 REDIS_HOST=127.0.0.1 diff --git a/app/Filters/QueryFilters.php b/app/Filters/QueryFilters.php index d1a16ffa1d21..e9370f56e49f 100644 --- a/app/Filters/QueryFilters.php +++ b/app/Filters/QueryFilters.php @@ -104,11 +104,11 @@ abstract class QueryFilters * @param string $value * @return stdClass */ - public function split($value) : stdClass + public function split($value) : \stdClass { $exploded_array = explode(':', $value); - $parts = new stdClass; + $parts = new \stdClass; $parts->value = $exploded_array[0]; $parts->operator = $this->operatorConvertor($exploded_array[1]); diff --git a/app/Http/Controllers/ImportController.php b/app/Http/Controllers/ImportController.php index 2d722ffb47bd..8d65b0e33d13 100644 --- a/app/Http/Controllers/ImportController.php +++ b/app/Http/Controllers/ImportController.php @@ -12,8 +12,11 @@ namespace App\Http\Controllers; use App\Http\Controllers\Controller; +use App\Http\Requests\Import\ImportRequest; use App\Http\Requests\Import\PreImportRequest; use App\Import\Definitions\Import\ImportMap; +use App\Import\Definitions\InvoiceMap; +use App\Jobs\Import\CSVImport; use Illuminate\Http\Request; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Str; @@ -90,6 +93,12 @@ class ImportController extends Controller return response()->json($data); } + public function import(ImportRequest $request) + { + CSVImport::dispatch($request, auth()->user()->company()); + + return response()->json(['message' => 'Importing data, email will be sent on completion'], 200); + } private function getCsvData($csvfile) { diff --git a/app/Http/Requests/Expense/UpdateExpenseRequest.php b/app/Http/Requests/Expense/UpdateExpenseRequest.php index 23cb149fdfbe..7e29f2fa811d 100644 --- a/app/Http/Requests/Expense/UpdateExpenseRequest.php +++ b/app/Http/Requests/Expense/UpdateExpenseRequest.php @@ -66,6 +66,10 @@ class UpdateExpenseRequest extends Request $input['category_id'] = $this->decodePrimaryKey($input['category_id']); } + if (! array_key_exists('currency_id', $input) || strlen($input['currency_id']) == 0) { + $input['currency_id'] = (string)auth()->user()->company()->settings->currency_id; + } + $this->replace($input); } } diff --git a/app/Http/Requests/Import/ImportRequest.php b/app/Http/Requests/Import/ImportRequest.php new file mode 100644 index 000000000000..a1f92a0dc465 --- /dev/null +++ b/app/Http/Requests/Import/ImportRequest.php @@ -0,0 +1,37 @@ +user()->isAdmin(); + } + + public function rules() + { + + return [ + 'hash' => 'required', + 'entity_type' => 'required', + ]; + + } +} diff --git a/app/Http/Requests/Import/PreImportRequest.php b/app/Http/Requests/Import/PreImportRequest.php index fdfb162e20af..b0f76e5637ce 100644 --- a/app/Http/Requests/Import/PreImportRequest.php +++ b/app/Http/Requests/Import/PreImportRequest.php @@ -12,7 +12,6 @@ namespace App\Http\Requests\Import; use App\Http\Requests\Request; -use App\Models\GroupSetting; class PreImportRequest extends Request { @@ -30,7 +29,8 @@ class PreImportRequest extends Request { return [ - 'file' => 'required|file|mimes:csv,txt' + 'file' => 'required|file|mimes:csv,txt', + 'entity_type' => 'required', ]; } diff --git a/app/Import/Definitions/InvoiceMap.php b/app/Import/Definitions/InvoiceMap.php index 8245bef32109..8a3c34a08539 100644 --- a/app/Import/Definitions/InvoiceMap.php +++ b/app/Import/Definitions/InvoiceMap.php @@ -17,41 +17,59 @@ class InvoiceMap public static function importable() { return [ - 0 => 'number', - 1 => 'user_id', - 2 => 'amount', - 3 => 'balance', - 4 => 'client_id', - 5 => 'status_id', - 6 => 'is_deleted', - 7 => 'discount', - 8 => 'po_number', - 9 => 'date', - 10 => 'due_date', - 11 => 'terms', - 12 => 'public_notes', - 13 => 'private_notes', - 14 => 'uses_inclusive_taxes', - 15 => 'tax_name1', - 16 => 'tax_rate1', - 17 => 'tax_name2', - 18 => 'tax_rate2', - 19 => 'tax_name3', - 20 => 'tax_rate3', - 21 => 'is_amount_discount', - 22 => 'footer', - 23 => 'partial', - 24 => 'partial_due_date', - 25 => 'custom_value1', - 26 => 'custom_value2', - 27 => 'custom_value3', - 28 => 'custom_value4', - 29 => 'custom_surcharge1', - 30 => 'custom_surcharge2', - 31 => 'custom_surcharge3', - 32 => 'custom_surcharge4', - 33 => 'exchange_rate', - 34 => 'line_items', + 0 => 'invoice.number', + 1 => 'invoice.user_id', + 2 => 'invoice.amount', + 3 => 'invoice.balance', + 4 => 'invoice.client_id', + 5 => 'invoice.discount', + 6 => 'invoice.po_number', + 7 => 'invoice.date', + 8 => 'invoice.due_date', + 9 => 'invoice.terms', + 10 => 'invoice.public_notes', + 11 => 'invoice.is_sent', + 12 => 'invoice.private_notes', + 13 => 'invoice.uses_inclusive_taxes', + 14 => 'invoice.tax_name1', + 15 => 'invoice.tax_rate1', + 16 => 'invoice.tax_name2', + 17 => 'invoice.tax_rate2', + 18 => 'invoice.tax_name3', + 19 => 'invoice.tax_rate3', + 20 => 'invoice.is_amount_discount', + 21 => 'invoice.footer', + 22 => 'invoice.partial', + 23 => 'invoice.partial_due_date', + 24 => 'invoice.custom_value1', + 25 => 'invoice.custom_value2', + 26 => 'invoice.custom_value3', + 27 => 'invoice.custom_value4', + 28 => 'invoice.custom_surcharge1', + 29 => 'invoice.custom_surcharge2', + 30 => 'invoice.custom_surcharge3', + 31 => 'invoice.custom_surcharge4', + 32 => 'invoice.exchange_rate', + 33 => 'payment.date', + 34 => 'payment.amount', + 35 => 'payment.transaction_reference', + 36 => 'item.quantity', + 37 => 'item.cost', + 38 => 'item.product_key', + 39 => 'item.notes', + 40 => 'item.discount', + 41 => 'item.is_amount_discount', + 42 => 'item.tax_name1', + 43 => 'item.tax_rate1', + 44 => 'item.tax_name2', + 45 => 'item.tax_rate2', + 46 => 'item.tax_name3', + 47 => 'item.tax_rate3', + 48 => 'item.custom_value1', + 49 => 'item.custom_value2', + 50 => 'item.custom_value3', + 51 => 'item.custom_value4', + 52 => 'item.type_id', ]; } @@ -63,36 +81,54 @@ class InvoiceMap 2 => 'texts.amount', 3 => 'texts.balance', 4 => 'texts.client', - 5 => 'texts.status', - 6 => 'texts.deleted', - 7 => 'texts.discount', - 8 => 'texts.po_number', - 9 => 'texts.date', - 10 => 'texts.due_date', - 11 => 'texts.terms', - 12 => 'texts.public_notes', - 13 => 'texts.private_notes', - 14 => 'texts.uses_inclusive_taxes', - 15 => 'texts.tax_name1', - 16 => 'texts.tax_rate', - 17 => 'texts.tax_name', - 18 => 'texts.tax_rate', - 19 => 'texts.tax_name', - 20 => 'texts.tax_rate', - 21 => 'texts.is_amount_discount', - 22 => 'texts.footer', - 23 => 'texts.partial', - 24 => 'texts.partial_due_date', - 25 => 'texts.custom_value1', - 26 => 'texts.custom_value2', - 27 => 'texts.custom_value3', - 28 => 'texts.custom_value4', + 5 => 'texts.discount', + 6 => 'texts.po_number', + 7 => 'texts.date', + 8 => 'texts.due_date', + 9 => 'texts.terms', + 10 => 'texts.public_notes', + 11 => 'texts.sent', + 12 => 'texts.private_notes', + 13 => 'texts.uses_inclusive_taxes', + 14 => 'texts.tax_name', + 15 => 'texts.tax_rate', + 16 => 'texts.tax_name', + 17 => 'texts.tax_rate', + 18 => 'texts.tax_name', + 19 => 'texts.tax_rate', + 20 => 'texts.is_amount_discount', + 21 => 'texts.footer', + 22 => 'texts.partial', + 23 => 'texts.partial_due_date', + 24 => 'texts.custom_value1', + 25 => 'texts.custom_value2', + 26 => 'texts.custom_value3', + 27 => 'texts.custom_value4', + 28 => 'texts.surcharge', 29 => 'texts.surcharge', 30 => 'texts.surcharge', 31 => 'texts.surcharge', - 32 => 'texts.surcharge', - 33 => 'texts.exchange_rate', - 34 => 'texts.items', + 32 => 'texts.exchange_rate', + 33 => 'texts.payment_date', + 34 => 'texts.payment_amount', + 35 => 'texts.transaction_reference', + 36 => 'texts.quantity', + 37 => 'texts.cost', + 38 => 'texts.product_key', + 39 => 'texts.notes', + 40 => 'texts.discount', + 41 => 'texts.is_amount_discount', + 42 => 'texts.tax_name', + 43 => 'texts.tax_rate', + 44 => 'texts.tax_name', + 45 => 'texts.tax_rate', + 46 => 'texts.tax_name', + 47 => 'texts.tax_rate', + 48 => 'texts.custom_value', + 49 => 'texts.custom_value', + 50 => 'texts.custom_value', + 51 => 'texts.custom_value', + 52 => 'texts.type', ]; } } \ No newline at end of file diff --git a/app/Jobs/Import/CSVImport.php b/app/Jobs/Import/CSVImport.php new file mode 100644 index 000000000000..49657ce0d065 --- /dev/null +++ b/app/Jobs/Import/CSVImport.php @@ -0,0 +1,74 @@ +request = $request; + + $this->company = $company; + + $this->hash = $request->input('hash'); + + $this->entity_type = $request->input('entity_type'); + + $this->skip_headers = $request->input('skip_headers'); + } + + /** + * Execute the job. + * + * + * @return void + */ + public function handle() + { + MultiDB::setDb($this->company->db); + + } + + public function failed($exception) + { + + } + + private function getCsv() + { + $base64_encoded_csv = Cache::get($this->hash); + + return base64_decode($base64_encoded_csv); + } +} diff --git a/app/Jobs/Util/Import.php b/app/Jobs/Util/Import.php index e8aea5395052..01976d36ffbf 100644 --- a/app/Jobs/Util/Import.php +++ b/app/Jobs/Util/Import.php @@ -104,6 +104,7 @@ class Import implements ShouldQueue * @var array */ private $available_imports = [ + 'account', 'company', 'users', 'payment_terms', @@ -225,6 +226,13 @@ class Import implements ShouldQueue }); } + private function processAccount(array $data) :void + { + $account = $this->company->account; + $account->fill($data); + $account->save(); + } + /** * @param array $data * @throws Exception diff --git a/app/Models/Company.php b/app/Models/Company.php index 1a00725cebf1..2f769887b229 100644 --- a/app/Models/Company.php +++ b/app/Models/Company.php @@ -79,6 +79,7 @@ class Company extends BaseModel 'invoice_task_timelog', 'auto_start_tasks', 'is_disabled', + 'default_task_is_date_based', ]; protected $hidden = [ diff --git a/app/Models/Task.php b/app/Models/Task.php index 39fd8127888c..d290bcadef8d 100644 --- a/app/Models/Task.php +++ b/app/Models/Task.php @@ -38,6 +38,7 @@ class Task extends BaseModel 'invoice_documents', 'rate', 'number', + 'is_date_based', ]; protected $touches = []; diff --git a/app/Transformers/CompanyTransformer.php b/app/Transformers/CompanyTransformer.php index c2e21c9229a5..46eb495b7dd8 100644 --- a/app/Transformers/CompanyTransformer.php +++ b/app/Transformers/CompanyTransformer.php @@ -146,6 +146,7 @@ class CompanyTransformer extends EntityTransformer 'invoice_task_documents' => (bool) $company->invoice_task_documents, 'show_tasks_table' => (bool) $company->show_tasks_table, 'use_credits_payment' => 'always', //todo remove + 'default_task_is_date_based' => (bool)$company->default_task_is_date_based, ]; } diff --git a/app/Transformers/TaskTransformer.php b/app/Transformers/TaskTransformer.php index 427c7a86b222..3b3ea7309830 100644 --- a/app/Transformers/TaskTransformer.php +++ b/app/Transformers/TaskTransformer.php @@ -66,6 +66,7 @@ class TaskTransformer extends EntityTransformer 'custom_value4' => $task->custom_value4 ?: '', 'status_id' => $this->encodePrimaryKey($task->status_id) ?: '', 'status_sort_order' => (int) $task->status_sort_order, + 'is_date_based' => (bool) $task->is_date_based, ]; } } diff --git a/app/Utils/Traits/ClientGroupSettingsSaver.php b/app/Utils/Traits/ClientGroupSettingsSaver.php index 94b8c239ae0b..16845ca696aa 100644 --- a/app/Utils/Traits/ClientGroupSettingsSaver.php +++ b/app/Utils/Traits/ClientGroupSettingsSaver.php @@ -63,6 +63,14 @@ trait ClientGroupSettingsSaver $entity_settings->{$key} = $value; } + //this pass will handle any null values that are in the translations + foreach ($settings->translations as $key => $value) { + if (is_null($settings->translations[$key])) + $settings->translations[$key] = ''; + } + + $entity_settings->translations = $settings->translations; + $entity->settings = $entity_settings; $entity->save(); diff --git a/app/Utils/Traits/CompanySettingsSaver.php b/app/Utils/Traits/CompanySettingsSaver.php index b096baaeb6a4..04443461cf28 100644 --- a/app/Utils/Traits/CompanySettingsSaver.php +++ b/app/Utils/Traits/CompanySettingsSaver.php @@ -58,6 +58,14 @@ trait CompanySettingsSaver } } + //this pass will handle any null values that are in the translations + foreach ($settings->translations as $key => $value) { + if (is_null($settings->translations[$key])) + $settings->translations[$key] = ''; + } + + $company_settings->translations = $settings->translations; + $entity->settings = $company_settings; $entity->save(); diff --git a/composer.lock b/composer.lock index 578bffb04798..3f3672951596 100644 --- a/composer.lock +++ b/composer.lock @@ -116,16 +116,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.168.3", + "version": "3.169.0", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "49ef1f905388c8185012c9651b80941b8f2a218d" + "reference": "d15a231355e4435fc33bab83df075ec31edd0a9b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/49ef1f905388c8185012c9651b80941b8f2a218d", - "reference": "49ef1f905388c8185012c9651b80941b8f2a218d", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/d15a231355e4435fc33bab83df075ec31edd0a9b", + "reference": "d15a231355e4435fc33bab83df075ec31edd0a9b", "shasum": "" }, "require": { @@ -200,9 +200,9 @@ "support": { "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.168.3" + "source": "https://github.com/aws/aws-sdk-php/tree/3.169.0" }, - "time": "2020-12-11T19:12:18+00:00" + "time": "2020-12-14T19:12:33+00:00" }, { "name": "brick/math", @@ -4019,16 +4019,16 @@ }, { "name": "monolog/monolog", - "version": "2.1.1", + "version": "2.2.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "f9eee5cec93dfb313a38b6b288741e84e53f02d5" + "reference": "1cb1cde8e8dd0f70cc0fe51354a59acad9302084" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/f9eee5cec93dfb313a38b6b288741e84e53f02d5", - "reference": "f9eee5cec93dfb313a38b6b288741e84e53f02d5", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/1cb1cde8e8dd0f70cc0fe51354a59acad9302084", + "reference": "1cb1cde8e8dd0f70cc0fe51354a59acad9302084", "shasum": "" }, "require": { @@ -4041,16 +4041,17 @@ "require-dev": { "aws/aws-sdk-php": "^2.4.9 || ^3.0", "doctrine/couchdb": "~1.0@dev", - "elasticsearch/elasticsearch": "^6.0", + "elasticsearch/elasticsearch": "^7", "graylog2/gelf-php": "^1.4.2", + "mongodb/mongodb": "^1.8", "php-amqplib/php-amqplib": "~2.4", "php-console/php-console": "^3.1.3", - "php-parallel-lint/php-parallel-lint": "^1.0", "phpspec/prophecy": "^1.6.1", + "phpstan/phpstan": "^0.12.59", "phpunit/phpunit": "^8.5", "predis/predis": "^1.1", "rollbar/rollbar": "^1.3", - "ruflin/elastica": ">=0.90 <3.0", + "ruflin/elastica": ">=0.90 <7.0.1", "swiftmailer/swiftmailer": "^5.3|^6.0" }, "suggest": { @@ -4070,7 +4071,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.x-dev" + "dev-main": "2.x-dev" } }, "autoload": { @@ -4086,11 +4087,11 @@ { "name": "Jordi Boggiano", "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" + "homepage": "https://seld.be" } ], "description": "Sends your logs to files, sockets, inboxes, databases and various web services", - "homepage": "http://github.com/Seldaek/monolog", + "homepage": "https://github.com/Seldaek/monolog", "keywords": [ "log", "logging", @@ -4098,7 +4099,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/2.1.1" + "source": "https://github.com/Seldaek/monolog/tree/2.2.0" }, "funding": [ { @@ -4110,7 +4111,7 @@ "type": "tidelift" } ], - "time": "2020-07-23T08:41:23+00:00" + "time": "2020-12-14T13:15:25+00:00" }, { "name": "mtdowling/jmespath.php", @@ -11469,16 +11470,16 @@ }, { "name": "phar-io/version", - "version": "3.0.3", + "version": "3.0.4", "source": { "type": "git", "url": "https://github.com/phar-io/version.git", - "reference": "726c026815142e4f8677b7cb7f2249c9ffb7ecae" + "reference": "e4782611070e50613683d2b9a57730e9a3ba5451" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/726c026815142e4f8677b7cb7f2249c9ffb7ecae", - "reference": "726c026815142e4f8677b7cb7f2249c9ffb7ecae", + "url": "https://api.github.com/repos/phar-io/version/zipball/e4782611070e50613683d2b9a57730e9a3ba5451", + "reference": "e4782611070e50613683d2b9a57730e9a3ba5451", "shasum": "" }, "require": { @@ -11514,9 +11515,9 @@ "description": "Library for handling version information and constraints", "support": { "issues": "https://github.com/phar-io/version/issues", - "source": "https://github.com/phar-io/version/tree/3.0.3" + "source": "https://github.com/phar-io/version/tree/3.0.4" }, - "time": "2020-11-30T09:21:21+00:00" + "time": "2020-12-13T23:18:30+00:00" }, { "name": "php-cs-fixer/diff", diff --git a/database/migrations/2020_12_14_114722_task_fields.php b/database/migrations/2020_12_14_114722_task_fields.php new file mode 100644 index 000000000000..bcb861986bf0 --- /dev/null +++ b/database/migrations/2020_12_14_114722_task_fields.php @@ -0,0 +1,36 @@ +boolean('is_date_based')->default(false); + }); + + Schema::table('companies', function (Blueprint $table) { + $table->boolean('default_task_is_date_based')->default(false); + }); + + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index 565053ca7601..56845222f440 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -3325,5 +3325,5 @@ return [ 'custom_value3' => 'Custom Value', 'custom_value4' => 'Custom Value', 'inclusive_taxes' => 'Include taxes', - + 'sort_order' => 'Sort Order', ];