diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bcbb19f476f2..b4748d96356a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -41,8 +41,7 @@ jobs: - name: Cleanup Builds run: | sudo rm -rf bootstrap/cache/* - sudo rm public/index.html - + - name: Build project # This would actually build your project, using zip for an example artifact run: | zip -r ./invoiceninja.zip ./ diff --git a/app/Events/Client/ClientWasDeleted.php b/app/Events/Client/ClientWasDeleted.php index 48fcaf25dca3..842a1d032646 100644 --- a/app/Events/Client/ClientWasDeleted.php +++ b/app/Events/Client/ClientWasDeleted.php @@ -12,6 +12,7 @@ namespace App\Events\Client; use App\Models\Client; +use App\Models\Company; use Illuminate\Queue\SerializesModels; /** diff --git a/app/Events/Client/ClientWasRestored.php b/app/Events/Client/ClientWasRestored.php index 505bf0f472a7..8f3f37f539f2 100644 --- a/app/Events/Client/ClientWasRestored.php +++ b/app/Events/Client/ClientWasRestored.php @@ -12,6 +12,7 @@ namespace App\Events\Client; use App\Models\Client; +use App\Models\Company; use Illuminate\Queue\SerializesModels; /** @@ -26,6 +27,8 @@ class ClientWasRestored */ public $client; + public $fromDeleted; + public $company; public $event_vars; @@ -37,9 +40,10 @@ class ClientWasRestored * @param Company $company * @param array $event_vars */ - public function __construct(Client $client, Company $company, array $event_vars) + public function __construct(Client $client, $fromDeleted, Company $company, array $event_vars) { $this->client = $client; + $this->fromDeleted = $fromDeleted; $this->company = $company; $this->event_vars = $event_vars; } diff --git a/app/Events/Client/ClientWasUpdated.php b/app/Events/Client/ClientWasUpdated.php index 419fea23353a..c249acb9750d 100644 --- a/app/Events/Client/ClientWasUpdated.php +++ b/app/Events/Client/ClientWasUpdated.php @@ -12,6 +12,7 @@ namespace App\Events\Client; use App\Models\Client; +use App\Models\Company; use Illuminate\Queue\SerializesModels; /** diff --git a/app/Events/Credit/CreditWasRestored.php b/app/Events/Credit/CreditWasRestored.php index f526ed5d515b..70ba1d5fd463 100644 --- a/app/Events/Credit/CreditWasRestored.php +++ b/app/Events/Credit/CreditWasRestored.php @@ -11,6 +11,7 @@ namespace App\Events\Credit; +use App\Models\Company; use App\Models\Credit; use Illuminate\Queue\SerializesModels; @@ -30,6 +31,7 @@ class CreditWasRestored public $event_vars; + public $fromDeleted; /** * Create a new event instance. * @@ -37,9 +39,10 @@ class CreditWasRestored * @param Company $company * @param array $event_vars */ - public function __construct(Credit $credit, Company $company, array $event_vars) + public function __construct(Credit $credit, $fromDeleted, Company $company, array $event_vars) { $this->credit = $credit; + $this->fromDeleted = $fromDeleted; $this->company = $company; $this->event_vars = $event_vars; } diff --git a/app/Events/Design/DesignWasRestored.php b/app/Events/Design/DesignWasRestored.php index 0de7dd749987..34cca273a55c 100644 --- a/app/Events/Design/DesignWasRestored.php +++ b/app/Events/Design/DesignWasRestored.php @@ -32,6 +32,7 @@ class DesignWasRestored public $event_vars; + public $fromDeleted; /** * Create a new event instance. * @@ -39,10 +40,12 @@ class DesignWasRestored * @param Company $company * @param array $event_vars */ - public function __construct(Design $design, Company $company, array $event_vars) + public function __construct(Design $design, $fromDeleted, Company $company, array $event_vars) { $this->design = $design; + $this->fromDeleted = $fromDeleted; + $this->company = $company; $this->event_vars = $event_vars; diff --git a/app/Events/Document/DocumentWasRestored.php b/app/Events/Document/DocumentWasRestored.php index 672d6273e062..4cc21da2859f 100644 --- a/app/Events/Document/DocumentWasRestored.php +++ b/app/Events/Document/DocumentWasRestored.php @@ -31,6 +31,7 @@ class DocumentWasRestored public $event_vars; + public $fromDeleted; /** * Create a new event instance. * @@ -38,9 +39,10 @@ class DocumentWasRestored * @param Company $company * @param array $event_vars */ - public function __construct(Document $document, Company $company, array $event_vars) + public function __construct(Document $document, $fromDeleted, Company $company, array $event_vars) { $this->document = $document; + $this->fromDeleted = $fromDeleted; $this->company = $company; $this->event_vars = $event_vars; } diff --git a/app/Events/Expense/ExpenseWasRestored.php b/app/Events/Expense/ExpenseWasRestored.php index e00342f1a1fe..b844a13d5c84 100644 --- a/app/Events/Expense/ExpenseWasRestored.php +++ b/app/Events/Expense/ExpenseWasRestored.php @@ -31,6 +31,7 @@ class ExpenseWasRestored public $event_vars; + public $fromDeleted; /** * Create a new event instance. * @@ -38,9 +39,10 @@ class ExpenseWasRestored * @param Company $company * @param array $event_vars */ - public function __construct(Expense $expense, Company $company, array $event_vars) + public function __construct(Expense $expense, $fromDeleted, Company $company, array $event_vars) { $this->expense = $expense; + $this->fromDeleted = $fromDeleted; $this->company = $company; $this->event_vars = $event_vars; } diff --git a/app/Events/Invoice/InvoiceWasRestored.php b/app/Events/Invoice/InvoiceWasRestored.php index bd246e298c97..885193b4e8bd 100644 --- a/app/Events/Invoice/InvoiceWasRestored.php +++ b/app/Events/Invoice/InvoiceWasRestored.php @@ -32,7 +32,7 @@ class InvoiceWasRestored public $company; public $event_vars; - + /** * Create a new event instance. * diff --git a/app/Events/Product/ProductWasRestored.php b/app/Events/Product/ProductWasRestored.php new file mode 100644 index 000000000000..cc5c95b5b497 --- /dev/null +++ b/app/Events/Product/ProductWasRestored.php @@ -0,0 +1,49 @@ +product = $product; + $this->fromDeleted = $fromDeleted; + $this->company = $company; + $this->event_vars = $event_vars; + } +} diff --git a/app/Events/Quote/QuoteWasArchived.php b/app/Events/Quote/QuoteWasArchived.php index 03fd3a82d985..873fecb31ef3 100644 --- a/app/Events/Quote/QuoteWasArchived.php +++ b/app/Events/Quote/QuoteWasArchived.php @@ -12,6 +12,7 @@ namespace App\Events\Quote; use App\Models\Company; +use App\Models\Quote; use Illuminate\Queue\SerializesModels; class QuoteWasArchived diff --git a/app/Events/Quote/QuoteWasCreated.php b/app/Events/Quote/QuoteWasCreated.php index 49420e087749..0fc4155da2bb 100644 --- a/app/Events/Quote/QuoteWasCreated.php +++ b/app/Events/Quote/QuoteWasCreated.php @@ -12,6 +12,7 @@ namespace App\Events\Quote; use App\Models\Company; +use App\Models\Quote; use Illuminate\Queue\SerializesModels; /** diff --git a/app/Events/Quote/QuoteWasDeleted.php b/app/Events/Quote/QuoteWasDeleted.php index fdf3273b2bd7..9bfac894e092 100644 --- a/app/Events/Quote/QuoteWasDeleted.php +++ b/app/Events/Quote/QuoteWasDeleted.php @@ -12,6 +12,7 @@ namespace App\Events\Quote; use App\Models\Company; +use App\Models\Quote; use Illuminate\Queue\SerializesModels; /** diff --git a/app/Events/Quote/QuoteWasRestored.php b/app/Events/Quote/QuoteWasRestored.php index 48bed8389f9e..6f2e4dd97974 100644 --- a/app/Events/Quote/QuoteWasRestored.php +++ b/app/Events/Quote/QuoteWasRestored.php @@ -12,6 +12,7 @@ namespace App\Events\Quote; use App\Models\Company; +use App\Models\Quote; use Illuminate\Queue\SerializesModels; /** @@ -27,6 +28,7 @@ class QuoteWasRestored public $event_vars; + public $fromDeleted; /** * Create a new event instance. * @@ -34,9 +36,10 @@ class QuoteWasRestored * @param Company $company * @param array $event_vars */ - public function __construct(Quote $quote, Company $company, array $event_vars) + public function __construct(Quote $quote, $fromDeleted, Company $company, array $event_vars) { $this->quote = $quote; + $this->fromDeleted = $fromDeleted; $this->company = $company; $this->event_vars = $event_vars; } diff --git a/app/Events/Task/TaskWasRestored.php b/app/Events/Task/TaskWasRestored.php index a5fd02eae200..d0340f321d51 100644 --- a/app/Events/Task/TaskWasRestored.php +++ b/app/Events/Task/TaskWasRestored.php @@ -31,6 +31,7 @@ class TaskWasRestored public $event_vars; + public $fromDeleted; /** * Create a new event instance. * @@ -38,9 +39,10 @@ class TaskWasRestored * @param Company $company * @param array $event_vars */ - public function __construct(Task $task, Company $company, array $event_vars) + public function __construct(Task $task, $fromDeleted, Company $company, array $event_vars) { $this->task = $task; + $this->fromDeleted = $fromDeleted; $this->company = $company; $this->event_vars = $event_vars; } diff --git a/app/Events/Vendor/VendorWasRestored.php b/app/Events/Vendor/VendorWasRestored.php index de64cee44bd7..327d0972dee6 100644 --- a/app/Events/Vendor/VendorWasRestored.php +++ b/app/Events/Vendor/VendorWasRestored.php @@ -31,6 +31,7 @@ class VendorWasRestored public $event_vars; + public $fromDeleted; /** * Create a new event instance. * @@ -38,9 +39,10 @@ class VendorWasRestored * @param Company $company * @param array $event_vars */ - public function __construct(Vendor $vendor, Company $company, array $event_vars) + public function __construct(Vendor $vendor, $fromDeleted, Company $company, array $event_vars) { $this->vendor = $vendor; + $this->fromDeleted = $fromDeleted; $this->company = $company; $this->event_vars = $event_vars; } diff --git a/app/Factory/CloneQuoteToInvoiceFactory.php b/app/Factory/CloneQuoteToInvoiceFactory.php index 326c33489822..0c02506d2c08 100644 --- a/app/Factory/CloneQuoteToInvoiceFactory.php +++ b/app/Factory/CloneQuoteToInvoiceFactory.php @@ -27,6 +27,7 @@ class CloneQuoteToInvoiceFactory unset($quote_array['hashed_id']); unset($quote_array['invoice_id']); unset($quote_array['id']); + unset($quote_array['invitations']); foreach ($quote_array as $key => $value) { $invoice->{$key} = $value; diff --git a/app/Http/Controllers/ClientController.php b/app/Http/Controllers/ClientController.php index 1145b4421b59..cfd03203082e 100644 --- a/app/Http/Controllers/ClientController.php +++ b/app/Http/Controllers/ClientController.php @@ -13,6 +13,7 @@ namespace App\Http\Controllers; use App\DataMapper\ClientSettings; use App\Events\Client\ClientWasCreated; +use App\Events\Client\ClientWasUpdated; use App\Factory\ClientFactory; use App\Filters\ClientFilters; use App\Http\Requests\Client\BulkClientRequest; @@ -288,6 +289,8 @@ class ClientController extends BaseController $this->uploadLogo($request->file('company_logo'), $client->company, $client); + event(new ClientWasUpdated($client, $client->company, Ninja::eventVars())); + return $this->itemResponse($client->fresh()); } diff --git a/app/Http/Controllers/ClientPortal/QuoteController.php b/app/Http/Controllers/ClientPortal/QuoteController.php index 6d8a7b350e0e..30eb3e9738e4 100644 --- a/app/Http/Controllers/ClientPortal/QuoteController.php +++ b/app/Http/Controllers/ClientPortal/QuoteController.php @@ -109,8 +109,8 @@ class QuoteController extends Controller if ($process) { foreach ($quotes as $quote) { - $quote->service()->approve()->save(); - event(new QuoteWasApproved(auth()->user(), $quote, $quote->company, Ninja::eventVars())); + $quote->service()->approve(auth()->user())->save(); + event(new QuoteWasApproved($quote, $quote->company, Ninja::eventVars())); } return redirect() diff --git a/app/Http/Controllers/ExpenseController.php b/app/Http/Controllers/ExpenseController.php index 22f44344bbec..378ab06c6aff 100644 --- a/app/Http/Controllers/ExpenseController.php +++ b/app/Http/Controllers/ExpenseController.php @@ -11,6 +11,8 @@ namespace App\Http\Controllers; +use App\Events\Expense\ExpenseWasCreated; +use App\Events\Expense\ExpenseWasUpdated; use App\Factory\ExpenseFactory; use App\Filters\ExpenseFilters; use App\Http\Requests\Expense\CreateExpenseRequest; @@ -29,6 +31,7 @@ use App\Models\Size; use App\Repositories\BaseRepository; use App\Repositories\ExpenseRepository; use App\Transformers\ExpenseTransformer; +use App\Utils\Ninja; use App\Utils\Traits\BulkOptions; use App\Utils\Traits\MakesHash; use App\Utils\Traits\Uploadable; @@ -281,6 +284,8 @@ class ExpenseController extends BaseController $this->uploadLogo($request->file('company_logo'), $expense->company, $expense); + event(new ExpenseWasUpdated($expense, $expense->company, Ninja::eventVars())); + return $this->itemResponse($expense->fresh()); } @@ -373,6 +378,8 @@ class ExpenseController extends BaseController { $expense = $this->expense_repo->save($request->all(), ExpenseFactory::create(auth()->user()->company()->id, auth()->user()->id)); + event(new ExpenseWasCreated($expense, $expense->company, Ninja::eventVars())); + return $this->itemResponse($expense); } diff --git a/app/Http/Controllers/PaymentController.php b/app/Http/Controllers/PaymentController.php index 3b22ecb661ba..78caf1f26929 100644 --- a/app/Http/Controllers/PaymentController.php +++ b/app/Http/Controllers/PaymentController.php @@ -29,8 +29,10 @@ use App\Repositories\BaseRepository; use App\Repositories\PaymentRepository; use App\Transformers\PaymentTransformer; use App\Utils\Traits\MakesHash; +use App\Events\Payment\PaymentWasUpdated; use Illuminate\Http\Request; use Illuminate\Http\Response; +use App\Utils\Ninja; /** * Class PaymentController. @@ -379,6 +381,7 @@ class PaymentController extends BaseController $payment = $this->payment_repo->save($request->all(), $payment); + event(new PaymentWasUpdated($payment, $payment->company, Ninja::eventVars())); return $this->itemResponse($payment); } @@ -506,7 +509,8 @@ class PaymentController extends BaseController $payments->each(function ($payment, $key) use ($action) { if (auth()->user()->can('edit', $payment)) { - $this->payment_repo->{$action}($payment); + $this->performAction($payment, $action, true); + // $this->payment_repo->{$action}($payment); } }); @@ -584,30 +588,31 @@ class PaymentController extends BaseController * @param Payment $payment * @param $action */ - public function action(ActionPaymentRequest $request, Payment $payment, $action) + public function performAction(Payment $payment, $action, $bulk = false) { switch ($action) { - case 'clone_to_invoice': - //$payment = CloneInvoiceFactory::create($payment, auth()->user()->id); - //return $this->itemResponse($payment); - break; - case 'clone_to_quote': - //$quote = CloneInvoiceToQuoteFactory::create($payment, auth()->user()->id); - // todo build the quote transformer and return response here - break; - case 'history': - // code... - break; - case 'delivery_note': - // code... - break; - case 'mark_paid': - // code... + case 'restore': + $this->payment_repo->restore($payment); + + if (! $bulk) { + return $this->listResponse($payment); + } + break; case 'archive': + $this->payment_repo->archive($payment); + + if (! $bulk) { + return $this->listResponse($payment); + } // code... break; case 'delete': + $this->payment_repo->delete($payment); + + if (! $bulk) { + return $this->listResponse($payment); + } // code... break; case 'email': diff --git a/app/Http/Controllers/QuoteController.php b/app/Http/Controllers/QuoteController.php index 6cf4cdd25744..a8d93a3e713c 100644 --- a/app/Http/Controllers/QuoteController.php +++ b/app/Http/Controllers/QuoteController.php @@ -11,6 +11,8 @@ namespace App\Http\Controllers; +use App\Events\Quote\QuoteWasCreated; +use App\Events\Quote\QuoteWasUpdated; use App\Factory\CloneInvoiceFactory; use App\Factory\CloneInvoiceToQuoteFactory; use App\Factory\CloneQuoteFactory; @@ -31,6 +33,7 @@ use App\Models\Quote; use App\Repositories\QuoteRepository; use App\Transformers\InvoiceTransformer; use App\Transformers\QuoteTransformer; +use App\Utils\Ninja; use App\Utils\TempFile; use App\Utils\Traits\MakesHash; use Illuminate\Http\Request; @@ -204,6 +207,8 @@ class QuoteController extends BaseController $quote = $this->quote_repo->save($request->all(), QuoteFactory::create(auth()->user()->company()->id, auth()->user()->id)); + event(new QuoteWasCreated($quote, $quote->company, Ninja::eventVars())); + return $this->itemResponse($quote); } @@ -378,6 +383,8 @@ class QuoteController extends BaseController $quote = $this->quote_repo->save($request->all(), $quote); + event(new QuoteWasUpdated($quote, $quote->company, Ninja::eventVars())); + return $this->itemResponse($quote); } @@ -658,15 +665,26 @@ class QuoteController extends BaseController }, basename($quote->pdf_file_path())); //return response()->download(TempFile::path($quote->pdf_file_path()), basename($quote->pdf_file_path())); break; + case 'restore': + $this->quote_repo->restore($quote); + + if (!$bulk) + return $this->listResponse($quote); + + break; case 'archive': $this->quote_repo->archive($quote); - return $this->listResponse($quote); + if (!$bulk) + return $this->listResponse($quote); + break; case 'delete': $this->quote_repo->delete($quote); - return $this->listResponse($quote); + if (!$bulk) + return $this->listResponse($quote); + break; case 'email': $quote->service()->sendEmail(); @@ -679,6 +697,7 @@ class QuoteController extends BaseController if (! $bulk) { return $this->itemResponse($quote); } + break; // no break default: return response()->json(['message' => "The requested action `{$action}` is not available."], 400); diff --git a/app/Http/Controllers/TaskController.php b/app/Http/Controllers/TaskController.php index 06322ca27eb6..928249a95701 100644 --- a/app/Http/Controllers/TaskController.php +++ b/app/Http/Controllers/TaskController.php @@ -11,6 +11,8 @@ namespace App\Http\Controllers; +use App\Events\Task\TaskWasCreated; +use App\Events\Task\TaskWasUpdated; use App\Factory\TaskFactory; use App\Filters\TaskFilters; use App\Http\Requests\Task\CreateTaskRequest; @@ -24,11 +26,12 @@ use App\Jobs\Util\ProcessBulk; use App\Jobs\Util\UploadAvatar; use App\Models\Country; use App\Models\Currency; -use App\Models\Task; use App\Models\Size; +use App\Models\Task; use App\Repositories\BaseRepository; use App\Repositories\TaskRepository; use App\Transformers\TaskTransformer; +use App\Utils\Ninja; use App\Utils\Traits\BulkOptions; use App\Utils\Traits\MakesHash; use App\Utils\Traits\Uploadable; @@ -278,6 +281,8 @@ class TaskController extends BaseController $task = $this->task_repo->save($request->all(), $task); + event(new TaskWasUpdated($task, $task->company, Ninja::eventVars())); + return $this->itemResponse($task->fresh()); } @@ -370,6 +375,8 @@ class TaskController extends BaseController { $task = $this->task_repo->save($request->all(), TaskFactory::create(auth()->user()->company()->id, auth()->user()->id)); + event(new TaskWasCreated($task, $task->company, Ninja::eventVars())); + return $this->itemResponse($task); } diff --git a/app/Http/Controllers/VendorController.php b/app/Http/Controllers/VendorController.php index 3c1482febe19..3957179560e0 100644 --- a/app/Http/Controllers/VendorController.php +++ b/app/Http/Controllers/VendorController.php @@ -11,6 +11,8 @@ namespace App\Http\Controllers; +use App\Events\Vendor\VendorWasCreated; +use App\Events\Vendor\VendorWasUpdated; use App\Factory\VendorFactory; use App\Filters\VendorFilters; use App\Http\Requests\Vendor\CreateVendorRequest; @@ -29,6 +31,7 @@ use App\Models\Vendor; use App\Repositories\BaseRepository; use App\Repositories\VendorRepository; use App\Transformers\VendorTransformer; +use App\Utils\Ninja; use App\Utils\Traits\BulkOptions; use App\Utils\Traits\MakesHash; use App\Utils\Traits\Uploadable; @@ -280,6 +283,8 @@ class VendorController extends BaseController $this->uploadLogo($request->file('company_logo'), $vendor->company, $vendor); + event(new VendorWasUpdated($vendor, $vendor->company, Ninja::eventVars())); + return $this->itemResponse($vendor->fresh()); } @@ -376,6 +381,8 @@ class VendorController extends BaseController $this->uploadLogo($request->file('company_logo'), $vendor->company, $vendor); + event(new VendorWasCreated($vendor, $vendor->company, Ninja::eventVars())); + return $this->itemResponse($vendor); } diff --git a/app/Http/Requests/Payment/StorePaymentRequest.php b/app/Http/Requests/Payment/StorePaymentRequest.php index 67c50a24e606..8b6ebbd65882 100644 --- a/app/Http/Requests/Payment/StorePaymentRequest.php +++ b/app/Http/Requests/Payment/StorePaymentRequest.php @@ -13,6 +13,7 @@ namespace App\Http\Requests\Payment; use App\Http\Requests\Request; use App\Http\ValidationRules\Credit\ValidCreditsRules; +use App\Http\ValidationRules\Credit\CreditsSumRule; use App\Http\ValidationRules\Payment\ValidInvoicesRules; use App\Http\ValidationRules\PaymentAmountsBalanceRule; use App\Http\ValidationRules\ValidCreditsPresentRule; @@ -76,7 +77,6 @@ class StorePaymentRequest extends Request } if (! isset($input['amount']) || $input['amount'] == 0) { - //$input['amount'] = $invoices_total - $credits_total; $input['amount'] = $invoices_total - $credits_total; //todo the payment amount is always less the credit amount applied } @@ -100,7 +100,7 @@ class StorePaymentRequest extends Request 'invoices.*.amount' => 'required', 'credits.*.credit_id' => 'bail|required|exists:credits,id', 'credits.*.credit_id' => new ValidCreditsRules($this->all()), - 'credits.*.amount' => 'required', + 'credits.*.amount' => ['required', new CreditsSumRule($this->all())], 'invoices' => new ValidPayableInvoicesRule(), 'number' => 'bail|nullable|unique:payments,number,'.$this->id.',id,company_id,'.$this->company_id, ]; diff --git a/app/Http/ValidationRules/Credit/CreditsSumRule.php b/app/Http/ValidationRules/Credit/CreditsSumRule.php new file mode 100644 index 000000000000..134a8bbe76b9 --- /dev/null +++ b/app/Http/ValidationRules/Credit/CreditsSumRule.php @@ -0,0 +1,59 @@ +input = $input; + } + + public function passes($attribute, $value) + { + return $this->checkCreditTotals(); + } + + private function checkCreditTotals() + { + + if( array_sum(array_column($this->input['credits'],'amount')) > array_sum(array_column($this->input['invoices'], 'amount'))) + return false; + + return true; + + } + + /** + * @return string + */ + public function message() + { + return "Total credits applied cannot be MORE than total of invoices"; + } +} diff --git a/app/Listeners/Activity/ClientUpdatedActivity.php b/app/Listeners/Activity/ClientUpdatedActivity.php new file mode 100644 index 000000000000..7bfdc5d2d755 --- /dev/null +++ b/app/Listeners/Activity/ClientUpdatedActivity.php @@ -0,0 +1,58 @@ +activity_repo = $activity_repo; + } + + /** + * Handle the event. + * + * @param object $event + * @return void + */ + public function handle($event) + { + MultiDB::setDb($event->company->db); + + $client = $event->client; + + $fields = new stdClass; + + $fields->client_id = $client->id; + $fields->user_id = $client->user_id; + $fields->company_id = $client->company_id; + $fields->activity_type_id = Activity::UPDATE_CLIENT; + + $this->activity_repo->save($fields, $client, $event->event_vars); + } +} diff --git a/app/Listeners/Activity/CreatedExpenseActivity.php b/app/Listeners/Activity/CreatedExpenseActivity.php new file mode 100644 index 000000000000..2753b6298505 --- /dev/null +++ b/app/Listeners/Activity/CreatedExpenseActivity.php @@ -0,0 +1,54 @@ +activity_repo = $activity_repo; + } + + /** + * Handle the event. + * + * @param object $event + * @return void + */ + public function handle($event) + { + MultiDB::setDb($event->company->db); + + $fields = new stdClass; + + $fields->expense_id = $event->expense->id; + $fields->user_id = $event->expense->user_id; + $fields->company_id = $event->expense->company_id; + $fields->activity_type_id = Activity::CREATE_EXPENSE; + + $this->activity_repo->save($fields, $event->expense, $event->event_vars); + } +} diff --git a/app/Listeners/Activity/CreatedTaskActivity.php b/app/Listeners/Activity/CreatedTaskActivity.php new file mode 100644 index 000000000000..70ee99e5ddc4 --- /dev/null +++ b/app/Listeners/Activity/CreatedTaskActivity.php @@ -0,0 +1,54 @@ +activity_repo = $activity_repo; + } + + /** + * Handle the event. + * + * @param object $event + * @return void + */ + public function handle($event) + { + MultiDB::setDb($event->company->db); + + $fields = new stdClass; + + $fields->task_id = $event->task->id; + $fields->user_id = $event->task->user_id; + $fields->company_id = $event->task->company_id; + $fields->activity_type_id = Activity::CREATE_TASK; + + $this->activity_repo->save($fields, $event->task, $event->event_vars); + } +} diff --git a/app/Listeners/Activity/CreatedVendorActivity.php b/app/Listeners/Activity/CreatedVendorActivity.php new file mode 100644 index 000000000000..cb7b1a223c46 --- /dev/null +++ b/app/Listeners/Activity/CreatedVendorActivity.php @@ -0,0 +1,54 @@ +activity_repo = $activity_repo; + } + + /** + * Handle the event. + * + * @param object $event + * @return void + */ + public function handle($event) + { + MultiDB::setDb($event->company->db); + + $fields = new stdClass; + + $fields->vendor_id = $event->vendor->id; + $fields->user_id = $event->vendor->user_id; + $fields->company_id = $event->vendor->company_id; + $fields->activity_type_id = Activity::CREATE_VENDOR; + + $this->activity_repo->save($fields, $event->vendor, $event->event_vars); + } +} diff --git a/app/Listeners/Activity/ExpenseArchivedActivity.php b/app/Listeners/Activity/ExpenseArchivedActivity.php new file mode 100644 index 000000000000..0d6a43ddfec7 --- /dev/null +++ b/app/Listeners/Activity/ExpenseArchivedActivity.php @@ -0,0 +1,58 @@ +activity_repo = $activity_repo; + } + + /** + * Handle the event. + * + * @param object $event + * @return void + */ + public function handle($event) + { + MultiDB::setDb($event->company->db); + + $expense = $event->expense; + + $fields = new stdClass; + + $fields->expense_id = $expense->id; + $fields->user_id = $expense->user_id; + $fields->company_id = $expense->company_id; + $fields->activity_type_id = Activity::ARCHIVE_EXPENSE; + + $this->activity_repo->save($fields, $expense, $event->event_vars); + } +} diff --git a/app/Listeners/Activity/ExpenseDeletedActivity.php b/app/Listeners/Activity/ExpenseDeletedActivity.php new file mode 100644 index 000000000000..477e783a6ac7 --- /dev/null +++ b/app/Listeners/Activity/ExpenseDeletedActivity.php @@ -0,0 +1,58 @@ +activity_repo = $activity_repo; + } + + /** + * Handle the event. + * + * @param object $event + * @return void + */ + public function handle($event) + { + MultiDB::setDb($event->company->db); + + $fields = new stdClass; + + $fields->expense_id = $event->expense->id; + $fields->user_id = $event->expense->user_id; + $fields->company_id = $event->expense->company_id; + $fields->activity_type_id = Activity::DELETE_VENDOR; + + $this->activity_repo->save($fields, $event->expense, $event->event_vars); + } +} diff --git a/app/Listeners/Activity/ExpenseRestoredActivity.php b/app/Listeners/Activity/ExpenseRestoredActivity.php new file mode 100644 index 000000000000..c25fe9042864 --- /dev/null +++ b/app/Listeners/Activity/ExpenseRestoredActivity.php @@ -0,0 +1,58 @@ +activity_repo = $activity_repo; + } + + /** + * Handle the event. + * + * @param object $event + * @return void + */ + public function handle($event) + { + MultiDB::setDb($event->company->db); + + $fields = new stdClass; + + $fields->expense_id = $event->expense->id; + $fields->user_id = $event->expense->user_id; + $fields->company_id = $event->expense->company_id; + $fields->activity_type_id = Activity::RESTORE_EXPENSE; + + $this->activity_repo->save($fields, $event->expense, $event->event_vars); + } +} diff --git a/app/Listeners/Activity/ExpenseUpdatedActivity.php b/app/Listeners/Activity/ExpenseUpdatedActivity.php new file mode 100644 index 000000000000..9f82f9dea3f4 --- /dev/null +++ b/app/Listeners/Activity/ExpenseUpdatedActivity.php @@ -0,0 +1,58 @@ +activity_repo = $activity_repo; + } + + /** + * Handle the event. + * + * @param object $event + * @return void + */ + public function handle($event) + { + MultiDB::setDb($event->company->db); + + $expense = $event->expense; + + $fields = new stdClass; + + $fields->expense_id = $expense->id; + $fields->user_id = $expense->user_id; + $fields->company_id = $expense->company_id; + $fields->activity_type_id = Activity::UPDATE_EXPENSE; + + $this->activity_repo->save($fields, $expense, $event->event_vars); + } +} diff --git a/app/Listeners/Activity/TaskArchivedActivity.php b/app/Listeners/Activity/TaskArchivedActivity.php new file mode 100644 index 000000000000..e31935efdecd --- /dev/null +++ b/app/Listeners/Activity/TaskArchivedActivity.php @@ -0,0 +1,58 @@ +activity_repo = $activity_repo; + } + + /** + * Handle the event. + * + * @param object $event + * @return void + */ + public function handle($event) + { + MultiDB::setDb($event->company->db); + + $task = $event->task; + + $fields = new stdClass; + + $fields->task_id = $task->id; + $fields->user_id = $task->user_id; + $fields->company_id = $task->company_id; + $fields->activity_type_id = Activity::ARCHIVE_TASK; + + $this->activity_repo->save($fields, $task, $event->event_vars); + } +} diff --git a/app/Listeners/Activity/TaskDeletedActivity.php b/app/Listeners/Activity/TaskDeletedActivity.php new file mode 100644 index 000000000000..3b201b680f9f --- /dev/null +++ b/app/Listeners/Activity/TaskDeletedActivity.php @@ -0,0 +1,58 @@ +activity_repo = $activity_repo; + } + + /** + * Handle the event. + * + * @param object $event + * @return void + */ + public function handle($event) + { + MultiDB::setDb($event->company->db); + + $fields = new stdClass; + + $fields->task_id = $event->task->id; + $fields->user_id = $event->task->user_id; + $fields->company_id = $event->task->company_id; + $fields->activity_type_id = Activity::DELETE_TASK; + + $this->activity_repo->save($fields, $event->task, $event->event_vars); + } +} diff --git a/app/Listeners/Activity/TaskRestoredActivity.php b/app/Listeners/Activity/TaskRestoredActivity.php new file mode 100644 index 000000000000..1188dc2072d7 --- /dev/null +++ b/app/Listeners/Activity/TaskRestoredActivity.php @@ -0,0 +1,58 @@ +activity_repo = $activity_repo; + } + + /** + * Handle the event. + * + * @param object $event + * @return void + */ + public function handle($event) + { + MultiDB::setDb($event->company->db); + + $fields = new stdClass; + + $fields->task_id = $event->task->id; + $fields->user_id = $event->task->user_id; + $fields->company_id = $event->task->company_id; + $fields->activity_type_id = Activity::RESTORE_TASK; + + $this->activity_repo->save($fields, $event->task, $event->event_vars); + } +} diff --git a/app/Listeners/Activity/TaskUpdatedActivity.php b/app/Listeners/Activity/TaskUpdatedActivity.php new file mode 100644 index 000000000000..a503bc080195 --- /dev/null +++ b/app/Listeners/Activity/TaskUpdatedActivity.php @@ -0,0 +1,58 @@ +activity_repo = $activity_repo; + } + + /** + * Handle the event. + * + * @param object $event + * @return void + */ + public function handle($event) + { + MultiDB::setDb($event->company->db); + + $task = $event->task; + + $fields = new stdClass; + + $fields->task_id = $task->id; + $fields->user_id = $task->user_id; + $fields->company_id = $task->company_id; + $fields->activity_type_id = Activity::UPDATE_TASK; + + $this->activity_repo->save($fields, $task, $event->event_vars); + } +} diff --git a/app/Listeners/Activity/VendorArchivedActivity.php b/app/Listeners/Activity/VendorArchivedActivity.php new file mode 100644 index 000000000000..3cbcc4acf1cf --- /dev/null +++ b/app/Listeners/Activity/VendorArchivedActivity.php @@ -0,0 +1,58 @@ +activity_repo = $activity_repo; + } + + /** + * Handle the event. + * + * @param object $event + * @return void + */ + public function handle($event) + { + MultiDB::setDb($event->company->db); + + $vendor = $event->vendor; + + $fields = new stdClass; + + $fields->vendor_id = $vendor->id; + $fields->user_id = $vendor->user_id; + $fields->company_id = $vendor->company_id; + $fields->activity_type_id = Activity::ARCHIVE_VENDOR; + + $this->activity_repo->save($fields, $vendor, $event->event_vars); + } +} diff --git a/app/Listeners/Activity/VendorDeletedActivity.php b/app/Listeners/Activity/VendorDeletedActivity.php new file mode 100644 index 000000000000..5c2941afc481 --- /dev/null +++ b/app/Listeners/Activity/VendorDeletedActivity.php @@ -0,0 +1,58 @@ +activity_repo = $activity_repo; + } + + /** + * Handle the event. + * + * @param object $event + * @return void + */ + public function handle($event) + { + MultiDB::setDb($event->company->db); + + $fields = new stdClass; + + $fields->vendor_id = $event->vendor->id; + $fields->user_id = $event->vendor->user_id; + $fields->company_id = $event->vendor->company_id; + $fields->activity_type_id = Activity::DELETE_VENDOR; + + $this->activity_repo->save($fields, $event->vendor, $event->event_vars); + } +} diff --git a/app/Listeners/Activity/VendorRestoredActivity.php b/app/Listeners/Activity/VendorRestoredActivity.php new file mode 100644 index 000000000000..b14715736eca --- /dev/null +++ b/app/Listeners/Activity/VendorRestoredActivity.php @@ -0,0 +1,58 @@ +activity_repo = $activity_repo; + } + + /** + * Handle the event. + * + * @param object $event + * @return void + */ + public function handle($event) + { + MultiDB::setDb($event->company->db); + + $fields = new stdClass; + + $fields->vendor_id = $event->vendor->id; + $fields->user_id = $event->vendor->user_id; + $fields->company_id = $event->vendor->company_id; + $fields->activity_type_id = Activity::RESTORE_VENDOR; + + $this->activity_repo->save($fields, $event->vendor, $event->event_vars); + } +} diff --git a/app/Listeners/Activity/VendorUpdatedActivity.php b/app/Listeners/Activity/VendorUpdatedActivity.php new file mode 100644 index 000000000000..930e6be6f911 --- /dev/null +++ b/app/Listeners/Activity/VendorUpdatedActivity.php @@ -0,0 +1,58 @@ +activity_repo = $activity_repo; + } + + /** + * Handle the event. + * + * @param object $event + * @return void + */ + public function handle($event) + { + MultiDB::setDb($event->company->db); + + $vendor = $event->vendor; + + $fields = new stdClass; + + $fields->vendor_id = $vendor->id; + $fields->user_id = $vendor->user_id; + $fields->company_id = $vendor->company_id; + $fields->activity_type_id = Activity::UPDATE_VENDOR; + + $this->activity_repo->save($fields, $vendor, $event->event_vars); + } +} diff --git a/app/Models/Activity.php b/app/Models/Activity.php index 8ba4bf497480..e271bc920fb4 100644 --- a/app/Models/Activity.php +++ b/app/Models/Activity.php @@ -47,24 +47,24 @@ class Activity extends StaticModel const RESTORE_PAYMENT = 27; // const RESTORE_CREDIT = 28; // const APPROVE_QUOTE = 29; // - const CREATE_VENDOR = 30; - const ARCHIVE_VENDOR = 31; - const DELETE_VENDOR = 32; - const RESTORE_VENDOR = 33; - const CREATE_EXPENSE = 34; - const ARCHIVE_EXPENSE = 35; - const DELETE_EXPENSE = 36; - const RESTORE_EXPENSE = 37; + const CREATE_VENDOR = 30; // + const ARCHIVE_VENDOR = 31;// + const DELETE_VENDOR = 32;// + const RESTORE_VENDOR = 33;// + const CREATE_EXPENSE = 34;// + const ARCHIVE_EXPENSE = 35;// + const DELETE_EXPENSE = 36;// + const RESTORE_EXPENSE = 37;// const VOIDED_PAYMENT = 39; // const REFUNDED_PAYMENT = 40; // const FAILED_PAYMENT = 41; - const CREATE_TASK = 42; - const UPDATE_TASK = 43; - const ARCHIVE_TASK = 44; - const DELETE_TASK = 45; - const RESTORE_TASK = 46; - const UPDATE_EXPENSE = 47; + const CREATE_TASK = 42; // + const UPDATE_TASK = 43; // + const ARCHIVE_TASK = 44; // + const DELETE_TASK = 45; // + const RESTORE_TASK = 46; // + const UPDATE_EXPENSE = 47;// const CREATE_USER = 48; // only used in CreateUser::job const UPDATE_USER = 49; // not needed? @@ -77,6 +77,8 @@ class Activity extends StaticModel const REVERSED_INVOICE = 58; // const CANCELLED_INVOICE = 59; // const VIEW_CREDIT = 60; // + const UPDATE_CLIENT = 61; // + const UPDATE_VENDOR = 62; // protected $casts = [ 'is_system' => 'boolean', diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index 40bfe5214a59..6a0db9ffcaab 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -30,6 +30,11 @@ use App\Events\Credit\CreditWasRestored; use App\Events\Credit\CreditWasUpdated; use App\Events\Credit\CreditWasViewed; use App\Events\Design\DesignWasArchived; +use App\Events\Expense\ExpenseWasArchived; +use App\Events\Expense\ExpenseWasCreated; +use App\Events\Expense\ExpenseWasDeleted; +use App\Events\Expense\ExpenseWasRestored; +use App\Events\Expense\ExpenseWasUpdated; use App\Events\Invoice\InvoiceWasArchived; use App\Events\Invoice\InvoiceWasCancelled; use App\Events\Invoice\InvoiceWasCreated; @@ -57,16 +62,34 @@ use App\Events\Quote\QuoteWasEmailed; use App\Events\Quote\QuoteWasRestored; use App\Events\Quote\QuoteWasUpdated; use App\Events\Quote\QuoteWasViewed; +use App\Events\Task\TaskWasArchived; +use App\Events\Task\TaskWasCreated; +use App\Events\Task\TaskWasDeleted; +use App\Events\Task\TaskWasRestored; +use App\Events\Task\TaskWasUpdated; use App\Events\User\UserLoggedIn; use App\Events\User\UserWasCreated; use App\Events\User\UserWasDeleted; +use App\Events\Vendor\VendorWasArchived; +use App\Events\Vendor\VendorWasCreated; +use App\Events\Vendor\VendorWasDeleted; +use App\Events\Vendor\VendorWasRestored; +use App\Events\Vendor\VendorWasUpdated; use App\Listeners\Activity\ArchivedClientActivity; +use App\Listeners\Activity\ClientUpdatedActivity; use App\Listeners\Activity\CreatedClientActivity; use App\Listeners\Activity\CreatedCreditActivity; +use App\Listeners\Activity\CreatedExpenseActivity; use App\Listeners\Activity\CreatedQuoteActivity; +use App\Listeners\Activity\CreatedTaskActivity; +use App\Listeners\Activity\CreatedVendorActivity; use App\Listeners\Activity\CreditArchivedActivity; use App\Listeners\Activity\DeleteClientActivity; use App\Listeners\Activity\DeleteCreditActivity; +use App\Listeners\Activity\ExpenseArchivedActivity; +use App\Listeners\Activity\ExpenseDeletedActivity; +use App\Listeners\Activity\ExpenseRestoredActivity; +use App\Listeners\Activity\ExpenseUpdatedActivity; use App\Listeners\Activity\PaymentCreatedActivity; use App\Listeners\Activity\PaymentDeletedActivity; use App\Listeners\Activity\PaymentRefundedActivity; @@ -74,7 +97,15 @@ use App\Listeners\Activity\PaymentUpdatedActivity; use App\Listeners\Activity\PaymentVoidedActivity; use App\Listeners\Activity\QuoteUpdatedActivity; use App\Listeners\Activity\RestoreClientActivity; +use App\Listeners\Activity\TaskArchivedActivity; +use App\Listeners\Activity\TaskDeletedActivity; +use App\Listeners\Activity\TaskRestoredActivity; +use App\Listeners\Activity\TaskUpdatedActivity; use App\Listeners\Activity\UpdatedCreditActivity; +use App\Listeners\Activity\VendorArchivedActivity; +use App\Listeners\Activity\VendorDeletedActivity; +use App\Listeners\Activity\VendorRestoredActivity; +use App\Listeners\Activity\VendorUpdatedActivity; use App\Listeners\Contact\UpdateContactLastLogin; use App\Listeners\Credit\CreditRestoredActivity; use App\Listeners\Credit\CreditViewedActivity; @@ -161,6 +192,7 @@ class EventServiceProvider extends ServiceProvider ArchivedClientActivity::class, ], ClientWasUpdated::class =>[ + ClientUpdatedActivity::class, ], ClientWasDeleted::class =>[ DeleteClientActivity::class, @@ -204,14 +236,29 @@ class EventServiceProvider extends ServiceProvider CreditViewedActivity::class, ], //Designs - DesignWasArchived::class => [ - ], DesignWasUpdated::class => [ ], + DesignWasArchived::class => [ + ], DesignWasDeleted::class => [ ], DesignWasRestored::class => [ ], + ExpenseWasCreated::class => [ + CreatedExpenseActivity::class, + ], + ExpenseWasUpdated::class => [ + ExpenseUpdatedActivity::class, + ], + ExpenseWasArchived::class => [ + ExpenseArchivedActivity::class, + ], + ExpenseWasDeleted::class => [ + ExpenseDeletedActivity::class, + ], + ExpenseWasRestored::class => [ + ExpenseRestoredActivity::class + ], //Invoices InvoiceWasMarkedSent::class => [ CreateInvoiceHtmlBackup::class, @@ -286,6 +333,37 @@ class EventServiceProvider extends ServiceProvider QuoteWasRestored::class => [ QuoteRestoredActivity::class, ], + TaskWasCreated::class => [ + CreatedTaskActivity::class, + ], + TaskWasUpdated::class => [ + TaskUpdatedActivity::class, + ], + TaskWasArchived::class => [ + TaskArchivedActivity::class, + ], + TaskWasDeleted::class => [ + TaskDeletedActivity::class, + ], + TaskWasRestored::class => [ + TaskRestoredActivity::class, + ], + VendorWasCreated::class => [ + CreatedVendorActivity::class, + ], + VendorWasArchived::class => [ + VendorArchivedActivity::class, + ], + VendorWasDeleted::class => [ + VendorDeletedActivity::class, + ], + VendorWasRestored::class => [ + VendorRestoredActivity::class, + ], + VendorWasUpdated::class => [ + VendorUpdatedActivity::class, + ], + ]; /** diff --git a/app/Repositories/BaseRepository.php b/app/Repositories/BaseRepository.php index 582dd5165d55..553b869e51a1 100644 --- a/app/Repositories/BaseRepository.php +++ b/app/Repositories/BaseRepository.php @@ -60,7 +60,7 @@ class BaseRepository */ private function getEventClass($entity, $type) { - return 'App\Events\\'.ucfirst(class_basename($entity)).'Was'.$type; + return 'App\Events\\'.ucfirst(class_basename($entity)).'\\'.ucfirst(class_basename($entity)).'Was'.$type; } /** diff --git a/app/Repositories/TaskRepository.php b/app/Repositories/TaskRepository.php index e73f3109a357..639567c25686 100644 --- a/app/Repositories/TaskRepository.php +++ b/app/Repositories/TaskRepository.php @@ -51,7 +51,7 @@ class TaskRepository extends BaseRepository $task->fill($data); $task->save(); - $task->number = empty($task->number) ? $this->getNextTaskNumber($task) : $data['number']; + $task->number = empty($task->number) || !array_key_exists('number', $data) ? $this->getNextTaskNumber($task) : $data['number']; if (isset($data['description'])) { $task->description = trim($data['description']); diff --git a/app/Services/Quote/ConvertQuote.php b/app/Services/Quote/ConvertQuote.php index be13069ab525..f8a757c5e57f 100644 --- a/app/Services/Quote/ConvertQuote.php +++ b/app/Services/Quote/ConvertQuote.php @@ -34,6 +34,7 @@ class ConvertQuote public function run($quote) { $invoice = CloneQuoteToInvoiceFactory::create($quote, $quote->user_id); + $invoice = $this->invoice_repo->save([], $invoice); $invoice->fresh(); diff --git a/app/Services/Quote/QuoteService.php b/app/Services/Quote/QuoteService.php index 72aade07b952..f74dd3cfe590 100644 --- a/app/Services/Quote/QuoteService.php +++ b/app/Services/Quote/QuoteService.php @@ -11,12 +11,14 @@ namespace App\Services\Quote; +use App\Events\Quote\QuoteWasApproved; use App\Factory\CloneQuoteToInvoiceFactory; use App\Models\Invoice; use App\Models\Quote; use App\Repositories\QuoteRepository; use App\Services\Quote\CreateInvitations; use App\Services\Quote\GetQuotePdf; +use App\Utils\Ninja; class QuoteService { @@ -108,10 +110,15 @@ class QuoteService return $this; } - public function approve() :self + public function approve($contact = null) :self { $this->setStatus(Quote::STATUS_APPROVED)->save(); + if(!$contact) + $contact = $this->quote->invitations->first()->contact; + + event(new QuoteWasApproved($contact, $this->quote, $this->quote->company, Ninja::eventVars())); + $invoice = null; if ($this->quote->client->getSetting('auto_convert_quote')) { diff --git a/app/Transformers/InvoiceTransformer.php b/app/Transformers/InvoiceTransformer.php index d4a308730bb7..27aa879b2c37 100644 --- a/app/Transformers/InvoiceTransformer.php +++ b/app/Transformers/InvoiceTransformer.php @@ -127,8 +127,8 @@ class InvoiceTransformer extends EntityTransformer 'custom_value2' => (string) $invoice->custom_value2 ?: '', 'custom_value3' => (string) $invoice->custom_value3 ?: '', 'custom_value4' => (string) $invoice->custom_value4 ?: '', - 'has_tasks' => (bool) $invoice->has_tasks, - 'has_expenses' => (bool) $invoice->has_expenses, + 'has_tasks' => (bool) false, //@deprecated v5.0.23 + 'has_expenses' => (bool) false, //@deprecated v5.0.23 'custom_surcharge1' => (float) $invoice->custom_surcharge1, 'custom_surcharge2' => (float) $invoice->custom_surcharge2, 'custom_surcharge3' => (float) $invoice->custom_surcharge3, diff --git a/app/Utils/HtmlEngine.php b/app/Utils/HtmlEngine.php index 8269c8127cd9..e7e75a6c5764 100644 --- a/app/Utils/HtmlEngine.php +++ b/app/Utils/HtmlEngine.php @@ -105,11 +105,11 @@ class HtmlEngine $data['$total_tax_values'] = ['value' => $this->totalTaxValues(), 'label' => ctrans('texts.taxes')]; $data['$line_tax_labels'] = ['value' => $this->lineTaxLabels(), 'label' => ctrans('texts.taxes')]; $data['$line_tax_values'] = ['value' => $this->lineTaxValues(), 'label' => ctrans('texts.taxes')]; - $data['$date'] = ['value' => $this->formatDate($this->entity->date, $this->client->date_format()) ?: ' ', 'label' => ctrans('texts.date')]; + $data['$date'] = ['value' => $this->formatDate($this->entity->date, $this->entity->client->date_format()) ?: ' ', 'label' => ctrans('texts.date')]; //$data['$invoice_date'] = ['value' => $this->date ?: ' ', 'label' => ctrans('texts.invoice_date')]; $data['$invoice.date'] = &$data['$date']; - $data['$due_date'] = ['value' => $this->formatDate($this->entity->due_date, $this->client->date_format()) ?: ' ', 'label' => ctrans('texts.'.$this->entity_string.'_due_date')]; - $data['$payment_due'] = ['value' => $this->formatDate($this->entity->due_date, $this->client->date_format()) ?: ' ', 'label' => ctrans('texts.payment_due')]; + $data['$due_date'] = ['value' => $this->formatDate($this->entity->due_date, $this->entity->client->date_format()) ?: ' ', 'label' => ctrans('texts.'.$this->entity_string.'_due_date')]; + $data['$payment_due'] = ['value' => $this->formatDate($this->entity->due_date, $this->entity->client->date_format()) ?: ' ', 'label' => ctrans('texts.payment_due')]; $data['$invoice.due_date'] = &$data['$due_date']; $data['$invoice.number'] = ['value' => $this->entity->number ?: ' ', 'label' => ctrans('texts.invoice_number')]; $data['$invoice.po_number'] = ['value' => $this->entity->po_number ?: ' ', 'label' => ctrans('texts.po_number')]; @@ -169,7 +169,7 @@ class HtmlEngine $data['$credit.number'] = ['value' => $this->entity->number ?: ' ', 'label' => ctrans('texts.credit_number')]; $data['$credit.total'] = &$data['$credit.total']; $data['$credit.po_number'] = &$data['$invoice.po_number']; - $data['$credit.date'] = ['value' => $this->formatDate($this->entity->date, $this->client->date_format()), 'label' => ctrans('texts.credit_date')]; + $data['$credit.date'] = ['value' => $this->formatDate($this->entity->date, $this->entity->client->date_format()), 'label' => ctrans('texts.credit_date')]; $data['$balance'] = ['value' => Number::formatMoney($this->entity_calc->getBalance(), $this->client) ?: ' ', 'label' => ctrans('texts.balance')]; $data['$credit.balance'] = &$data['$balance']; @@ -187,7 +187,7 @@ class HtmlEngine $data['$entity_issued_to'] = ['value' => '', 'label' => ctrans("texts.{$this->entity_string}_issued_to")]; $data['$your_entity'] = ['value' => '', 'label' => ctrans("texts.your_{$this->entity_string}")]; - $data['$quote.date'] = ['value' => $this->formatDate($this->entity->date, $this->client->date_format()) ?: ' ', 'label' => ctrans('texts.quote_date')]; + $data['$quote.date'] = ['value' => $this->formatDate($this->entity->date, $this->entity->client->date_format()) ?: ' ', 'label' => ctrans('texts.quote_date')]; $data['$quote.number'] = ['value' => $this->entity->number ?: ' ', 'label' => ctrans('texts.quote_number')]; $data['$quote.po_number'] = &$data['$invoice.po_number']; $data['$quote.quote_number'] = &$data['$quote.number']; diff --git a/tests/Feature/PaymentTest.php b/tests/Feature/PaymentTest.php index b9f36304697a..3b7d43e46a10 100644 --- a/tests/Feature/PaymentTest.php +++ b/tests/Feature/PaymentTest.php @@ -1302,4 +1302,87 @@ $contact = ClientContact::factory()->create([ $this->assertEquals(1, $payment->invoices()->count()); } } + + public function testPaymentActionArchive() + { + $this->invoice = null; + + $client = ClientFactory::create($this->company->id, $this->user->id); + $client->save(); + + $this->invoice = InvoiceFactory::create($this->company->id, $this->user->id); //stub the company and user_id + $this->invoice->client_id = $client->id; + + $this->invoice->line_items = $this->buildLineItems(); + $this->invoice->uses_inclusive_taxes = false; + + $this->invoice->save(); + + $this->invoice_calc = new InvoiceSum($this->invoice); + $this->invoice_calc->build(); + + $this->invoice = $this->invoice_calc->getInvoice(); + $this->invoice->save(); + $this->invoice->service()->markSent()->save(); + + $data = [ + 'amount' => 20.0, + 'client_id' => $this->encodePrimaryKey($client->id), + 'invoices' => [ + [ + 'invoice_id' => $this->encodePrimaryKey($this->invoice->id), + 'amount' => 10, + ], + ], + 'date' => '2019/12/12', + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/payments/', $data); + + $response->assertStatus(200); + + $arr = $response->json(); + + $payment_id = $arr['data']['id']; + + $payment = Payment::whereId($this->decodePrimaryKey($payment_id))->first(); + + + $data = [ + 'ids' => [$this->encodePrimaryKey($payment->id)], + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/payments/bulk?action=archive', $data); + + $arr = $response->json(); + + $this->assertGreaterThan(0, $arr['data'][0]['archived_at']); + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/payments/bulk?action=restore', $data); + + $arr = $response->json(); + + $this->assertEquals(0, $arr['data'][0]['archived_at']); + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/payments/bulk?action=delete', $data); + + $arr = $response->json(); + + $this->assertEquals(1, $arr['data'][0]['is_deleted']); + } + + + } diff --git a/tests/Integration/EventTest.php b/tests/Integration/EventTest.php new file mode 100644 index 000000000000..991a6254f5be --- /dev/null +++ b/tests/Integration/EventTest.php @@ -0,0 +1,596 @@ +faker = \Faker\Factory::create(); + + $this->makeTestData(); + } + + public function testExpenseEvents() + { + $this->expectsEvents([ + ExpenseWasCreated::class, + ExpenseWasUpdated::class, + ExpenseWasArchived::class, + ExpenseWasRestored::class, + ExpenseWasDeleted::class, + ]); + + $data = [ + 'public_notes' => $this->faker->firstName, + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/expenses/', $data) + ->assertStatus(200); + + + $arr = $response->json(); + + $data = [ + 'public_notes' => $this->faker->firstName, + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->put('/api/v1/expenses/' . $arr['data']['id'], $data) + ->assertStatus(200); + + + $data = [ + 'ids' => [$arr['data']['id']], + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/expenses/bulk?action=archive', $data) + ->assertStatus(200); + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/expenses/bulk?action=restore', $data) + ->assertStatus(200); + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/expenses/bulk?action=delete', $data) + ->assertStatus(200); + + } + + + public function testVendorEvents() + { + $this->expectsEvents([ + VendorWasCreated::class, + VendorWasUpdated::class, + VendorWasArchived::class, + VendorWasRestored::class, + VendorWasDeleted::class, + ]); + + $data = [ + 'name' => $this->faker->firstName, + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/vendors/', $data) + ->assertStatus(200); + + + $arr = $response->json(); + + $data = [ + 'name' => $this->faker->firstName, + 'id_number' => 'Coolio', + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->put('/api/v1/vendors/' . $arr['data']['id'], $data) + ->assertStatus(200); + + + $data = [ + 'ids' => [$arr['data']['id']], + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/vendors/bulk?action=archive', $data) + ->assertStatus(200); + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/vendors/bulk?action=restore', $data) + ->assertStatus(200); + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/vendors/bulk?action=delete', $data) + ->assertStatus(200); + + } + + + public function testTaskEvents() + { + + /* Test fire new invoice */ + $data = [ + 'client_id' => $this->client->hashed_id, + 'description' => 'dude', + ]; + + $this->expectsEvents([ + TaskWasCreated::class, + TaskWasUpdated::class, + TaskWasArchived::class, + TaskWasRestored::class, + TaskWasDeleted::class, + ]); + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/tasks/', $data) + ->assertStatus(200); + + + $arr = $response->json(); + + $data = [ + 'client_id' => $this->client->hashed_id, + 'description' => 'dude2', + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->put('/api/v1/tasks/' . $arr['data']['id'], $data) + ->assertStatus(200); + + + $data = [ + 'ids' => [$arr['data']['id']], + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/tasks/bulk?action=archive', $data) + ->assertStatus(200); + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/tasks/bulk?action=restore', $data) + ->assertStatus(200); + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/tasks/bulk?action=delete', $data) + ->assertStatus(200); + + } + + public function testCreditEvents() + { + + /* Test fire new invoice */ + $data = [ + 'client_id' => $this->client->hashed_id, + 'number' => 'dude', + ]; + + $this->expectsEvents([ + CreditWasCreated::class, + CreditWasUpdated::class, + CreditWasArchived::class, + CreditWasRestored::class, + CreditWasDeleted::class, + ]); + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/credits/', $data) + ->assertStatus(200); + + + $arr = $response->json(); + + $data = [ + 'client_id' => $this->client->hashed_id, + 'number' => 'dude2', + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->put('/api/v1/credits/' . $arr['data']['id'], $data) + ->assertStatus(200); + + + $data = [ + 'ids' => [$arr['data']['id']], + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/credits/bulk?action=archive', $data) + ->assertStatus(200); + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/credits/bulk?action=restore', $data) + ->assertStatus(200); + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/credits/bulk?action=delete', $data) + ->assertStatus(200); + + } + + public function testQuoteEvents() + { + + /* Test fire new invoice */ + $data = [ + 'client_id' => $this->client->hashed_id, + 'number' => 'dude', + ]; + + $this->expectsEvents([ + QuoteWasCreated::class, + QuoteWasUpdated::class, + QuoteWasArchived::class, + QuoteWasRestored::class, + QuoteWasDeleted::class, + QuoteWasApproved::class, + ]); + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/quotes/', $data) + ->assertStatus(200); + + + $arr = $response->json(); + + $data = [ + 'client_id' => $this->client->hashed_id, + 'number' => 'dude2', + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->put('/api/v1/quotes/' . $arr['data']['id'], $data) + ->assertStatus(200); + + + $data = [ + 'ids' => [$arr['data']['id']], + ]; + + $quote = Quote::find($this->decodePrimaryKey($arr['data']['id'])); + $quote->status_id = Quote::STATUS_SENT; + $quote->save(); + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/quotes/bulk?action=archive', $data) + ->assertStatus(200); + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/quotes/bulk?action=restore', $data) + ->assertStatus(200); + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/quotes/bulk?action=approve', $data) + ->assertStatus(200); + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/quotes/bulk?action=delete', $data) + ->assertStatus(200); + + } + + + //@TODO paymentwasvoided + //@TODO paymentwasrefunded + + public function testPaymentEvents() + { + + $this->expectsEvents([ + PaymentWasCreated::class, + PaymentWasUpdated::class, + PaymentWasArchived::class, + PaymentWasRestored::class, + PaymentWasDeleted::class, + ]); + + $data = [ + 'amount' => $this->invoice->amount, + 'client_id' => $this->client->hashed_id, + 'invoices' => [ + [ + 'invoice_id' => $this->invoice->hashed_id, + 'amount' => $this->invoice->amount, + ], + ], + 'date' => '2020/12/12', + + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/payments?include=invoices', $data) + ->assertStatus(200); + + $arr = $response->json(); + + $data = [ + 'transaction_reference' => 'testing' + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->put('/api/v1/payments/' . $arr['data']['id'], $data) + ->assertStatus(200); + + $data = [ + 'ids' => [$arr['data']['id']], + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/payments/bulk?action=archive', $data) + ->assertStatus(200); + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/payments/bulk?action=restore', $data) + ->assertStatus(200); + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/payments/bulk?action=delete', $data) + ->assertStatus(200); + } + + + public function testInvoiceEvents() + { + + /* Test fire new invoice */ + $data = [ + 'client_id' => $this->client->hashed_id, + 'number' => 'dude', + ]; + + $this->expectsEvents([ + InvoiceWasCreated::class, + InvoiceWasUpdated::class, + InvoiceWasArchived::class, + InvoiceWasRestored::class, + InvoiceWasDeleted::class, + ]); + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/invoices/', $data) + ->assertStatus(200); + + + $arr = $response->json(); + + $data = [ + 'client_id' => $this->client->hashed_id, + 'number' => 'dude2', + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->put('/api/v1/invoices/' . $arr['data']['id'], $data) + ->assertStatus(200); + + + $data = [ + 'ids' => [$arr['data']['id']], + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/invoices/bulk?action=archive', $data) + ->assertStatus(200); + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/invoices/bulk?action=restore', $data) + ->assertStatus(200); + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/invoices/bulk?action=delete', $data) + ->assertStatus(200); + + } + + + public function testClientEvents() + { + $this->expectsEvents([ + ClientWasCreated::class, + ClientWasUpdated::class, + ClientWasArchived::class, + ClientWasRestored::class, + ClientWasDeleted::class, + ]); + + $data = [ + 'name' => $this->faker->firstName, + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/clients/', $data) + ->assertStatus(200); + + + $arr = $response->json(); + + $data = [ + 'name' => $this->faker->firstName, + 'id_number' => 'Coolio', + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->put('/api/v1/clients/' . $arr['data']['id'], $data) + ->assertStatus(200); + + + $data = [ + 'ids' => [$arr['data']['id']], + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/clients/bulk?action=archive', $data) + ->assertStatus(200); + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/clients/bulk?action=restore', $data) + ->assertStatus(200); + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/clients/bulk?action=delete', $data) + ->assertStatus(200); + + } + +}