Invoice projects

This commit is contained in:
David Bomba 2024-11-13 07:34:21 +11:00
parent 29ef8566f1
commit cdc63b101f
6 changed files with 148 additions and 12 deletions

View File

@ -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);
}
}

View File

@ -0,0 +1,43 @@
<?php
/**
* Project Ninja (https://paymentninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2022. Project Ninja LLC (https://paymentninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\Http\Requests\Project;
use App\Http\Requests\Request;
class InvoiceProjectRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize(): bool
{
/** @var \App\Models\User $user */
$user = auth()->user();
return $user->can('edit', $this->project);
}
public function rules()
{
return [];
}
public function prepareForValidation()
{
$input = $this->all();
$this->replace($input);
}
}

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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;
}
}