diff --git a/app/Http/Controllers/ProjectController.php b/app/Http/Controllers/ProjectController.php index 2559d01adf..b41d043b36 100644 --- a/app/Http/Controllers/ProjectController.php +++ b/app/Http/Controllers/ProjectController.php @@ -11,25 +11,29 @@ namespace App\Http\Controllers; + +use App\Models\Account; +use App\Models\Invoice; +use App\Models\Project; +use Illuminate\Http\Response; use App\Factory\ProjectFactory; use App\Filters\ProjectFilters; +use App\Utils\Traits\MakesHash; +use App\Utils\Traits\SavesDocuments; +use App\Utils\Traits\GeneratesCounter; +use App\Repositories\ProjectRepository; +use App\Transformers\ProjectTransformer; +use App\Services\Template\TemplateAction; use App\Http\Requests\Project\BulkProjectRequest; -use App\Http\Requests\Project\CreateProjectRequest; -use App\Http\Requests\Project\DestroyProjectRequest; use App\Http\Requests\Project\EditProjectRequest; use App\Http\Requests\Project\ShowProjectRequest; use App\Http\Requests\Project\StoreProjectRequest; +use App\Http\Requests\Project\CreateProjectRequest; use App\Http\Requests\Project\UpdateProjectRequest; use App\Http\Requests\Project\UploadProjectRequest; -use App\Models\Account; -use App\Models\Project; -use App\Repositories\ProjectRepository; -use App\Services\Template\TemplateAction; -use App\Transformers\ProjectTransformer; -use App\Utils\Traits\GeneratesCounter; -use App\Utils\Traits\MakesHash; -use App\Utils\Traits\SavesDocuments; -use Illuminate\Http\Response; +use App\Http\Requests\Project\DestroyProjectRequest; +use App\Http\Requests\Project\InvoiceProjectRequest; +use App\Transformers\InvoiceTransformer; /** * Class ProjectController. @@ -590,4 +594,14 @@ class ProjectController extends BaseController return $this->itemResponse($project->fresh()); } + + public function invoice(InvoiceProjectRequest $request, Project $project) + { + $this->entity_transformer = InvoiceTransformer::class; + $this->entity_type = Invoice::class; + + $invoice = $this->project_repo->invoice($project); + + return $this->itemResponse($invoice); + } } diff --git a/app/Http/Requests/Project/InvoiceProjectRequest.php b/app/Http/Requests/Project/InvoiceProjectRequest.php new file mode 100644 index 0000000000..50b1766194 --- /dev/null +++ b/app/Http/Requests/Project/InvoiceProjectRequest.php @@ -0,0 +1,43 @@ +user(); + + return $user->can('edit', $this->project); + } + + public function rules() + { + return []; + } + + public function prepareForValidation() + { + $input = $this->all(); + + $this->replace($input); + + } +} diff --git a/app/Jobs/Ninja/CheckCompanyData.php b/app/Jobs/Ninja/CheckCompanyData.php index 34577d0171..4072e14323 100644 --- a/app/Jobs/Ninja/CheckCompanyData.php +++ b/app/Jobs/Ninja/CheckCompanyData.php @@ -63,7 +63,6 @@ class CheckCompanyData implements ShouldQueue $this->checkPaidToDates(); $this->checkClientBalances(); $this->checkContacts(); - $this->checkCompanyData(); if (Cache::has($this->hash)) { $cache_instance = Cache::get($this->hash); diff --git a/app/Models/Expense.php b/app/Models/Expense.php index 9ed0d58dce..20fa0a196f 100644 --- a/app/Models/Expense.php +++ b/app/Models/Expense.php @@ -257,4 +257,19 @@ class Expense extends BaseModel return ctrans('texts.logged'); } + + public function calculated_tax_rate($tax_amount, $tax_rate): float + { + + if ($this->calculate_tax_by_amount) { + if ($this->uses_inclusive_taxes) { + return round((($tax_amount / $this->amount) * 100 * 1000) / 10) / 100; + } + + return round((($tax_amount / $this->amount) * 1000) / 10) / 1; + } + + return $tax_rate; + + } } diff --git a/app/Models/Task.php b/app/Models/Task.php index 86ddcc5b67..20fe2d39be 100644 --- a/app/Models/Task.php +++ b/app/Models/Task.php @@ -305,6 +305,11 @@ class Task extends BaseModel } + public function getQuantity(): float + { + return round(($this->calcDuration() / 3600) , 2); + } + public function taskValue(): float { return round(($this->calcDuration() / 3600) * $this->getRate(), 2); diff --git a/app/Repositories/ProjectRepository.php b/app/Repositories/ProjectRepository.php index b804230eef..d5d4d57f54 100644 --- a/app/Repositories/ProjectRepository.php +++ b/app/Repositories/ProjectRepository.php @@ -11,6 +11,9 @@ namespace App\Repositories; +use App\DataMapper\InvoiceItem; +use App\Factory\InvoiceFactory; +use App\Models\Product; use App\Models\Project; /** @@ -18,4 +21,61 @@ use App\Models\Project; */ class ProjectRepository extends BaseRepository { + public function invoice(Project $project) + { + $invoice = InvoiceFactory::create($project->company_id, $project->user_id); + $invoice->client_id = $project->client_id; + $lines = []; + + $uninvoiced_tasks = $project->tasks() + ->withTrashed() + ->whereNull('invoice_id') + ->where('is_deleted',0) + ->cursor() + ->each(function ($task) use(&$lines){ + + $item = new InvoiceItem(); + $item->type_id = '2'; + $item->cost = $task->getRate(); + $item->product_key = ''; + $item->notes = ''; + $item->quantity = $task->getQuantity(); + $item->task_id = $task->hashed_id; + $item->tax_id = (string) Product::PRODUCT_TYPE_SERVICE; + + $lines[] = $item; + + }); + + $unpaid_expenses = $project->expenses() + ->withTrashed() + ->where('should_be_invoiced', true) + ->whereNull('payment_date') + ->cursor() + ->each(function ($expense) use(&$lines){ + + $item = new InvoiceItem(); + $item->cost = $expense->amount; + $item->product_key = ''; + $item->notes = $expense->public_notes; + $item->quantity = 1; + $item->tax_name1 = $expense->tax_name1; + $item->tax_rate1 = $expense->calculatedTaxRate($expense->tax_amount1, $expense->tax_rate1); + + $item->tax_name2 = $expense->tax_name2; + $item->tax_rate2 = $expense->calculatedTaxRate($expense->tax_amount2, $expense->tax_rate2); + + $item->tax_name3 = $expense->tax_name3; + $item->tax_rate3 = $expense->calculatedTaxRate($expense->tax_amount3, $expense->tax_rate3); + $item->tax_id = (string) Product::PRODUCT_TYPE_PHYSICAL; + $item->expense_id = $expense->hashed_id; + $item->type_id = '1'; + + $lines[] = $item; + }); + + $invoice->line_items = $lines; + return $invoice; + + } }