diff --git a/app/DataMapper/ClientSettings.php b/app/DataMapper/ClientSettings.php index 128a25b8c3ff..e5845a0c7ce0 100644 --- a/app/DataMapper/ClientSettings.php +++ b/app/DataMapper/ClientSettings.php @@ -59,9 +59,6 @@ class ClientSettings extends BaseSettings public $quote_number_prefix; public $quote_number_pattern; public $quote_number_counter; - - //public $client_number_prefix; - //public $client_number_pattern; public $credit_number_prefix; public $credit_number_pattern; diff --git a/app/Factory/PaymentFactory.php b/app/Factory/PaymentFactory.php new file mode 100644 index 000000000000..e626f4aa68e2 --- /dev/null +++ b/app/Factory/PaymentFactory.php @@ -0,0 +1,35 @@ +company_id = $company_id; + $payment->user_id = $user_id; + $payment->client_id = 0; + $payment->client_contact_id = null; + $payment->invitation_id = null; + $payment->account_gateway_id = null; + $payment->payment_type_id = null; + $payment->is_deleted = false; + $payment->amount = 0; + $payment->payment_date = null; + $payment->transaction_reference = null; + $payment->payer_id = null; + $payment->invoice_id = 0; + + return $payment; + } +} + + + diff --git a/app/Factory/RecurringInvoiceFactory.php b/app/Factory/RecurringInvoiceFactory.php new file mode 100644 index 000000000000..7e6d2b7b7952 --- /dev/null +++ b/app/Factory/RecurringInvoiceFactory.php @@ -0,0 +1,51 @@ +status_id = RecurringInvoice::STATUS_DRAFT; + $invoice->discount = 0; + $invoice->is_amount_discount = true; + $invoice->po_number = ''; + $invoice->footer = ''; + $invoice->terms = ''; + $invoice->public_notes = ''; + $invoice->private_notes = ''; + $invoice->invoice_date = null; + $invoice->due_date = null; + $invoice->partial_due_date = null; + $invoice->is_deleted = false; + $invoice->line_items = json_encode([]); + $invoice->settings = ClientSettings::buildClientSettings(new CompanySettings(CompanySettings::defaults()), new ClientSettings(ClientSettings::defaults())); //todo need to embed the settings here + $invoice->backup = json_encode([]); + $invoice->tax_name1 = ''; + $invoice->tax_rate1 = 0; + $invoice->tax_name2 = ''; + $invoice->tax_rate2 = 0; + $invoice->custom_value1 = 0; + $invoice->custom_value2 = 0; + $invoice->custom_value3 = 0; + $invoice->custom_value4 = 0; + $invoice->amount = 0; + $invoice->balance = 0; + $invoice->partial = 0; + $invoice->user_id = $user_id; + $invoice->company_id = $company_id; + $invoice->frequency_id = RecurringInvoice::FREQUENCY_MONTHLY; + $invoice->start_date = null; + $invoice->last_sent_date = null; + $invoice->next_send_date = null; + $invoice->remaining_cycles = 0; + + return $invoice; + } + +} diff --git a/app/Filters/PaymentFilters.php b/app/Filters/PaymentFilters.php new file mode 100644 index 000000000000..90902314259c --- /dev/null +++ b/app/Filters/PaymentFilters.php @@ -0,0 +1,111 @@ +builder; + + return $this->builder->where(function ($query) use ($filter) { + $query->where('payments.custom_value1', 'like', '%'.$filter.'%') + ->orWhere('payments.custom_value2', 'like' , '%'.$filter.'%') + ->orWhere('payments.custom_value3', 'like' , '%'.$filter.'%') + ->orWhere('payments.custom_value4', 'like' , '%'.$filter.'%'); + }); + } + + /** + * Filters the list based on the status + * archived, active, deleted + * + * @param string filter + * @return Illuminate\Database\Query\Builder + */ + public function status(string $filter = '') : Builder + { + if(strlen($filter) == 0) + return $this->builder; + + $table = 'payments'; + $filters = explode(',', $filter); + + return $this->builder->where(function ($query) use ($filters, $table) { + $query->whereNull($table . '.id'); + + if (in_array(parent::STATUS_ACTIVE, $filters)) { + $query->orWhereNull($table . '.deleted_at'); + } + + if (in_array(parent::STATUS_ARCHIVED, $filters)) { + $query->orWhere(function ($query) use ($table) { + $query->whereNotNull($table . '.deleted_at'); + + if (! in_array($table, ['users'])) { + $query->where($table . '.is_deleted', '=', 0); + } + }); + } + + if (in_array(parent::STATUS_DELETED, $filters)) { + $query->orWhere($table . '.is_deleted', '=', 1); + } + }); + } + + /** + * Sorts the list based on $sort + * + * @param string sort formatted as column|asc + * @return Illuminate\Database\Query\Builder + */ + public function sort(string $sort) : Builder + { + $sort_col = explode("|", $sort); + return $this->builder->orderBy($sort_col[0], $sort_col[1]); + } + + /** + * Returns the base query + * + * @param int company_id + * @return Illuminate\Database\Query\Builder + * @deprecated + */ + public function baseQuery(int $company_id, User $user) : Builder + { + + } + + /** + * Filters the query by the users company ID + * + * @param $company_id The company Id + * @return Illuminate\Database\Query\Builder + */ + public function entityFilter() + { + + return $this->builder->whereCompanyId(auth()->user()->company()->id); + + } + +} \ No newline at end of file diff --git a/app/Filters/RecurringInvoiceFilters.php b/app/Filters/RecurringInvoiceFilters.php new file mode 100644 index 000000000000..b412dc7736c0 --- /dev/null +++ b/app/Filters/RecurringInvoiceFilters.php @@ -0,0 +1,111 @@ +builder; + + return $this->builder->where(function ($query) use ($filter) { + $query->where('recurring_invoices.custom_value1', 'like', '%'.$filter.'%') + ->orWhere('recurring_invoices.custom_value2', 'like' , '%'.$filter.'%') + ->orWhere('recurring_invoices.custom_value3', 'like' , '%'.$filter.'%') + ->orWhere('recurring_invoices.custom_value4', 'like' , '%'.$filter.'%'); + }); + } + + /** + * Filters the list based on the status + * archived, active, deleted + * + * @param string filter + * @return Illuminate\Database\Query\Builder + */ + public function status(string $filter = '') : Builder + { + if(strlen($filter) == 0) + return $this->builder; + + $table = 'recurring_'; + $filters = explode(',', $filter); + + return $this->builder->where(function ($query) use ($filters, $table) { + $query->whereNull($table . '.id'); + + if (in_array(parent::STATUS_ACTIVE, $filters)) { + $query->orWhereNull($table . '.deleted_at'); + } + + if (in_array(parent::STATUS_ARCHIVED, $filters)) { + $query->orWhere(function ($query) use ($table) { + $query->whereNotNull($table . '.deleted_at'); + + if (! in_array($table, ['users'])) { + $query->where($table . '.is_deleted', '=', 0); + } + }); + } + + if (in_array(parent::STATUS_DELETED, $filters)) { + $query->orWhere($table . '.is_deleted', '=', 1); + } + }); + } + + /** + * Sorts the list based on $sort + * + * @param string sort formatted as column|asc + * @return Illuminate\Database\Query\Builder + */ + public function sort(string $sort) : Builder + { + $sort_col = explode("|", $sort); + return $this->builder->orderBy($sort_col[0], $sort_col[1]); + } + + /** + * Returns the base query + * + * @param int company_id + * @return Illuminate\Database\Query\Builder + * @deprecated + */ + public function baseQuery(int $company_id, User $user) : Builder + { + + } + + /** + * Filters the query by the users company ID + * + * @param $company_id The company Id + * @return Illuminate\Database\Query\Builder + */ + public function entityFilter() + { + + return $this->builder->whereCompanyId(auth()->user()->company()->id); + + } + +} \ No newline at end of file diff --git a/app/Http/Controllers/PaymentController.php b/app/Http/Controllers/PaymentController.php new file mode 100644 index 000000000000..1e8866771492 --- /dev/null +++ b/app/Http/Controllers/PaymentController.php @@ -0,0 +1,233 @@ +payment_repo = $payment_repo; + + } + + /** + * Show the list of Invoices + * + * @param \App\Filters\PaymentFilters $filters The filters + * + * @return \Illuminate\Http\Response + */ + public function index(PaymentFilters $filters) + { + + $payments = Payment::filter($filters); + + return $this->listResponse($payments); + + } + + /** + * Show the form for creating a new resource. + * + * @param \App\Http\Requests\Payment\CreatePaymentRequest $request The request + * + * @return \Illuminate\Http\Response + */ + public function create(CreatePaymentRequest $request) + { + + $payment = PaymentFactory::create(auth()->user()->company()->id, auth()->user()->id); + + return $this->itemResponse($payment); + + } + + + /** + * Store a newly created resource in storage. + * + * @param \App\Http\Requests\Payment\StorePaymentRequest $request The request + * + * @return \Illuminate\Http\Response + */ + public function store(StorePaymentRequest $request) + { + + $payment = $this->payment_repo->save($request, PaymentFactory::create(auth()->user()->company()->id, auth()->user()->id)); + + return $this->itemResponse($payment); + + } + + /** + * Display the specified resource. + * + * @param \App\Http\Requests\Payment\ShowPaymentRequest $request The request + * @param \App\Models\Invoice $payment The invoice + * + * @return \Illuminate\Http\Response + */ + public function show(ShowPaymentRequest $request, Payment $payment) + { + + return $this->itemResponse($payment); + + } + + /** + * Show the form for editing the specified resource. + * + * @param \App\Http\Requests\Payment\EditPaymentRequest $request The request + * @param \App\Models\Invoice $payment The invoice + * + * @return \Illuminate\Http\Response + */ + public function edit(EditPaymentRequest $request, Payment $payment) + { + + return $this->itemResponse($payment); + + } + + /** + * Update the specified resource in storage. + * + * @param \App\Http\Requests\Payment\UpdatePaymentRequest $request The request + * @param \App\Models\Invoice $payment The invoice + * + * @return \Illuminate\Http\Response + */ + public function update(UpdatePaymentRequest $request, Payment $payment) + { + + $payment = $this->payment_repo->save(request(), $payment); + + return $this->itemResponse($payment); + + } + + /** + * Remove the specified resource from storage. + * + * @param \App\Http\Requests\Payment\DestroyPaymentRequest $request + * @param \App\Models\Invoice $payment + * + * @return \Illuminate\Http\Response + */ + public function destroy(DestroyPaymentRequest $request, Payment $payment) + { + + $payment->delete(); + + return response()->json([], 200); + + } + + /** + * Perform bulk actions on the list view + * + * @return Collection + */ + public function bulk() + { + + $action = request()->input('action'); + + $ids = request()->input('ids'); + + $payments = Payment::withTrashed()->find($ids); + + $payments->each(function ($payment, $key) use($action){ + + if(auth()->user()->can('edit', $payment)) + $this->payment_repo->{$action}($payment); + + }); + + //todo need to return the updated dataset + return $this->listResponse(Payment::withTrashed()->whereIn('id', $ids)); + + } + + public function action(ActionPaymentRequest $request, Payment $payment, $action) + { + + 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... + break; + case 'archive': + # code... + break; + case 'delete': + # code... + break; + case 'email': + //dispatch email to queue + break; + + default: + # code... + break; + } + } + +} diff --git a/app/Http/Controllers/RecurringInvoiceController.php b/app/Http/Controllers/RecurringInvoiceController.php index fe680cd059c4..9cd0543af6c6 100644 --- a/app/Http/Controllers/RecurringInvoiceController.php +++ b/app/Http/Controllers/RecurringInvoiceController.php @@ -2,83 +2,235 @@ namespace App\Http\Controllers; +use App\Factory\CloneRecurringInvoiceFactory; +use App\Factory\CloneRecurringInvoiceToQuoteFactory; +use App\Factory\RecurringInvoiceFactory; +use App\Filters\RecurringInvoiceFilters; +use App\Http\Requests\RecurringInvoice\ActionRecurringInvoiceRequest; +use App\Http\Requests\RecurringInvoice\CreateRecurringInvoiceRequest; +use App\Http\Requests\RecurringInvoice\DestroyRecurringInvoiceRequest; +use App\Http\Requests\RecurringInvoice\EditRecurringInvoiceRequest; +use App\Http\Requests\RecurringInvoice\ShowRecurringInvoiceRequest; +use App\Http\Requests\RecurringInvoice\StoreRecurringInvoiceRequest; +use App\Http\Requests\RecurringInvoice\UpdateRecurringInvoiceRequest; +use App\Jobs\Entity\ActionEntity; +use App\Models\RecurringInvoice; +use App\Repositories\BaseRepository; +use App\Repositories\RecurringInvoiceRepository; +use App\Transformers\RecurringInvoiceTransformer; +use App\Utils\Traits\MakesHash; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Log; -class RecurringInvoiceController extends Controller +/** + * Class RecurringInvoiceController + * @package App\Http\Controllers\RecurringInvoiceController + */ + +class RecurringInvoiceController extends BaseController { + + use MakesHash; + + protected $entity_type = RecurringInvoice::class; + + protected $entity_transformer = RecurringInvoiceTransformer::class; + /** - * Display a listing of the resource. + * @var RecurringInvoiceRepository + */ + protected $recurring_invoice_repo; + + protected $base_repo; + + /** + * RecurringInvoiceController constructor. + * + * @param \App\Repositories\RecurringInvoiceRepository $recurring_invoice_repo The RecurringInvoice repo + */ + public function __construct(RecurringInvoiceRepository $recurring_invoice_repo) + { + + parent::__construct(); + + $this->recurring_invoice_repo = $recurring_invoice_repo; + + } + + /** + * Show the list of recurring_invoices + * + * @param \App\Filters\RecurringInvoiceFilters $filters The filters * * @return \Illuminate\Http\Response */ - public function index() + public function index(RecurringInvoiceFilters $filters) { - // + + $recurring_invoices = RecurringInvoice::filter($filters); + + return $this->listResponse($recurring_invoices); + } /** * Show the form for creating a new resource. * + * @param \App\Http\Requests\RecurringInvoice\CreateRecurringInvoiceRequest $request The request + * * @return \Illuminate\Http\Response */ - public function create() + public function create(CreateRecurringInvoiceRequest $request) { - // + + $recurring_invoice = RecurringInvoiceFactory::create(auth()->user()->company()->id, auth()->user()->id); + + return $this->itemResponse($recurring_invoice); + } + /** * Store a newly created resource in storage. * - * @param \Illuminate\Http\Request $request + * @param \App\Http\Requests\RecurringInvoice\StoreRecurringInvoiceRequest $request The request + * * @return \Illuminate\Http\Response */ - public function store(Request $request) + public function store(StoreRecurringInvoiceRequest $request) { - // + + $recurring_invoice = $this->recurring_invoice_repo->save($request, RecurringInvoiceFactory::create(auth()->user()->company()->id, auth()->user()->id)); + + return $this->itemResponse($recurring_invoice); + } /** * Display the specified resource. * - * @param int $id + * @param \App\Http\Requests\RecurringInvoice\ShowRecurringInvoiceRequest $request The request + * @param \App\Models\RecurringInvoice $recurring_invoice The RecurringInvoice + * * @return \Illuminate\Http\Response */ - public function show($id) + public function show(ShowRecurringInvoiceRequest $request, RecurringInvoice $recurring_invoice) { - // + + return $this->itemResponse($recurring_invoice); + } /** * Show the form for editing the specified resource. * - * @param int $id + * @param \App\Http\Requests\RecurringInvoice\EditRecurringInvoiceRequest $request The request + * @param \App\Models\RecurringInvoice $recurring_invoice The RecurringInvoice + * * @return \Illuminate\Http\Response */ - public function edit($id) + public function edit(EditRecurringInvoiceRequest $request, RecurringInvoice $recurring_invoice) { - // - } + return $this->itemResponse($recurring_invoice); + + } + /** * Update the specified resource in storage. * - * @param \Illuminate\Http\Request $request - * @param int $id + * @param \App\Http\Requests\RecurringInvoice\UpdateRecurringInvoiceRequest $request The request + * @param \App\Models\RecurringInvoice $recurring_invoice The RecurringInvoice + * * @return \Illuminate\Http\Response */ - public function update(Request $request, $id) + public function update(UpdateRecurringInvoiceRequest $request, RecurringInvoice $recurring_invoice) { - // + + $recurring_invoice = $this->recurring_invoice_repo->save(request(), $recurring_invoice); + + return $this->itemResponse($recurring_invoice); + } /** * Remove the specified resource from storage. * - * @param int $id - * @return \Illuminate\Http\Response + * @param \App\Http\Requests\RecurringInvoice\DestroyRecurringInvoiceRequest $request + * @param \App\Models\RecurringInvoice $recurring_invoice + * + * @return \Illuminate\Http\Response */ - public function destroy($id) + public function destroy(DestroyRecurringInvoiceRequest $request, RecurringInvoice $recurring_invoice) { - // + + $recurring_invoice->delete(); + + return response()->json([], 200); + } + + /** + * Perform bulk actions on the list view + * + * @return Collection + */ + public function bulk() + { + + $action = request()->input('action'); + + $ids = request()->input('ids'); + + $recurring_invoices = RecurringInvoice::withTrashed()->find($ids); + + $recurring_invoices->each(function ($recurring_invoice, $key) use($action){ + + if(auth()->user()->can('edit', $recurring_invoice)) + $this->recurring_invoice_repo->{$action}($recurring_invoice); + + }); + + //todo need to return the updated dataset + return $this->listResponse(RecurringInvoice::withTrashed()->whereIn('id', $ids)); + + } + + public function action(ActionRecurringInvoiceRequest $request, RecurringInvoice $recurring_invoice, $action) + { + + switch ($action) { + case 'clone_to_RecurringInvoice': + // $recurring_invoice = CloneRecurringInvoiceFactory::create($recurring_invoice, auth()->user()->id); + // return $this->itemResponse($recurring_invoice); + break; + case 'clone_to_quote': + // $quote = CloneRecurringInvoiceToQuoteFactory::create($recurring_invoice, 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... + break; + case 'archive': + # code... + break; + case 'delete': + # code... + break; + case 'email': + //dispatch email to queue + break; + + default: + # code... + break; + } + } + } diff --git a/app/Http/Requests/Payment/ActionPaymentRequest.php b/app/Http/Requests/Payment/ActionPaymentRequest.php new file mode 100644 index 000000000000..d60bb3babdd4 --- /dev/null +++ b/app/Http/Requests/Payment/ActionPaymentRequest.php @@ -0,0 +1,21 @@ +user()->can('edit', $this->payment); + } + +} \ No newline at end of file diff --git a/app/Http/Requests/Payment/CreatePaymentRequest.php b/app/Http/Requests/Payment/CreatePaymentRequest.php new file mode 100644 index 000000000000..0c3c30b74749 --- /dev/null +++ b/app/Http/Requests/Payment/CreatePaymentRequest.php @@ -0,0 +1,21 @@ +user()->can('create', Payment::class); + } + +} \ No newline at end of file diff --git a/app/Http/Requests/Payment/DestroyPaymentRequest.php b/app/Http/Requests/Payment/DestroyPaymentRequest.php new file mode 100644 index 000000000000..34604ce5ea64 --- /dev/null +++ b/app/Http/Requests/Payment/DestroyPaymentRequest.php @@ -0,0 +1,21 @@ +user()->can('edit', $this->payment); + } + +} \ No newline at end of file diff --git a/app/Http/Requests/Payment/EditPaymentRequest.php b/app/Http/Requests/Payment/EditPaymentRequest.php new file mode 100644 index 000000000000..a336386d81ab --- /dev/null +++ b/app/Http/Requests/Payment/EditPaymentRequest.php @@ -0,0 +1,40 @@ +user()->can('edit', $this->payment); + } + + public function rules() + { + $rules = []; + + return $rules; + } + + + public function sanitize() + { + $input = $this->all(); + + //$input['id'] = $this->encodePrimaryKey($input['id']); + + //$this->replace($input); + + return $this->all(); + } + +} \ No newline at end of file diff --git a/app/Http/Requests/Payment/ShowPaymentRequest.php b/app/Http/Requests/Payment/ShowPaymentRequest.php new file mode 100644 index 000000000000..b9a5b998b8b2 --- /dev/null +++ b/app/Http/Requests/Payment/ShowPaymentRequest.php @@ -0,0 +1,21 @@ +user()->can('view', $this->payment); + } + +} \ No newline at end of file diff --git a/app/Http/Requests/Payment/StorePaymentRequest.php b/app/Http/Requests/Payment/StorePaymentRequest.php new file mode 100644 index 000000000000..2a1336aad191 --- /dev/null +++ b/app/Http/Requests/Payment/StorePaymentRequest.php @@ -0,0 +1,41 @@ +user()->can('create', Payment::class); + } + + public function rules() + { + return [ + 'documents' => 'mimes:png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx', + ]; + } + + + public function sanitize() + { + //do post processing of Payment request here, ie. Payment_items + } + + public function messages() + { + + } + + +} + diff --git a/app/Http/Requests/Payment/UpdatePaymentRequest.php b/app/Http/Requests/Payment/UpdatePaymentRequest.php new file mode 100644 index 000000000000..96c5fe59712c --- /dev/null +++ b/app/Http/Requests/Payment/UpdatePaymentRequest.php @@ -0,0 +1,31 @@ +user()->can('edit', $this->payment); + + } + + + public function rules() + { + return [ + 'documents' => 'mimes:png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx', + ]; + } + +} \ No newline at end of file diff --git a/app/Http/Requests/RecurringInvoice/ActionRecurringInvoiceRequest.php b/app/Http/Requests/RecurringInvoice/ActionRecurringInvoiceRequest.php new file mode 100644 index 000000000000..26ddad27aba2 --- /dev/null +++ b/app/Http/Requests/RecurringInvoice/ActionRecurringInvoiceRequest.php @@ -0,0 +1,21 @@ +user()->can('edit', $this->recurring_invoice); + } + +} \ No newline at end of file diff --git a/app/Http/Requests/RecurringInvoice/CreateRecurringInvoiceRequest.php b/app/Http/Requests/RecurringInvoice/CreateRecurringInvoiceRequest.php new file mode 100644 index 000000000000..2344cbad2051 --- /dev/null +++ b/app/Http/Requests/RecurringInvoice/CreateRecurringInvoiceRequest.php @@ -0,0 +1,21 @@ +user()->can('create', RecurringInvoice::class); + } + +} \ No newline at end of file diff --git a/app/Http/Requests/RecurringInvoice/DestroyRecurringInvoiceRequest.php b/app/Http/Requests/RecurringInvoice/DestroyRecurringInvoiceRequest.php new file mode 100644 index 000000000000..3e21d60e502b --- /dev/null +++ b/app/Http/Requests/RecurringInvoice/DestroyRecurringInvoiceRequest.php @@ -0,0 +1,21 @@ +user()->can('edit', $this->recurring_invoice); + } + +} \ No newline at end of file diff --git a/app/Http/Requests/RecurringInvoice/EditRecurringInvoiceRequest.php b/app/Http/Requests/RecurringInvoice/EditRecurringInvoiceRequest.php new file mode 100644 index 000000000000..5ed0432bcda4 --- /dev/null +++ b/app/Http/Requests/RecurringInvoice/EditRecurringInvoiceRequest.php @@ -0,0 +1,40 @@ +user()->can('edit', $this->recurring_invoice); + } + + public function rules() + { + $rules = []; + + return $rules; + } + + + public function sanitize() + { + $input = $this->all(); + + //$input['id'] = $this->encodePrimaryKey($input['id']); + + //$this->replace($input); + + return $this->all(); + } + +} \ No newline at end of file diff --git a/app/Http/Requests/RecurringInvoice/ShowRecurringInvoiceRequest.php b/app/Http/Requests/RecurringInvoice/ShowRecurringInvoiceRequest.php new file mode 100644 index 000000000000..4d3c8138ec8d --- /dev/null +++ b/app/Http/Requests/RecurringInvoice/ShowRecurringInvoiceRequest.php @@ -0,0 +1,21 @@ +user()->can('view', $this->recurring_invoice); + } + +} \ No newline at end of file diff --git a/app/Http/Requests/RecurringInvoice/StoreRecurringInvoiceRequest.php b/app/Http/Requests/RecurringInvoice/StoreRecurringInvoiceRequest.php new file mode 100644 index 000000000000..7be5d6bd89d4 --- /dev/null +++ b/app/Http/Requests/RecurringInvoice/StoreRecurringInvoiceRequest.php @@ -0,0 +1,41 @@ +user()->can('create', RecurringInvoice::class); + } + + public function rules() + { + return [ + 'documents' => 'mimes:png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx', + ]; + } + + + public function sanitize() + { + //do post processing of RecurringInvoice request here, ie. RecurringInvoice_items + } + + public function messages() + { + + } + + +} + diff --git a/app/Http/Requests/RecurringInvoice/UpdateRecurringInvoiceRequest.php b/app/Http/Requests/RecurringInvoice/UpdateRecurringInvoiceRequest.php new file mode 100644 index 000000000000..ec11b37cb677 --- /dev/null +++ b/app/Http/Requests/RecurringInvoice/UpdateRecurringInvoiceRequest.php @@ -0,0 +1,32 @@ +user()->can('edit', $this->recurring_invoice); + + } + + + public function rules() + { + return [ + 'documents' => 'mimes:png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx', + ]; + } + +} \ No newline at end of file diff --git a/app/Models/Payment.php b/app/Models/Payment.php index dab643fe3357..b32b69f967f0 100644 --- a/app/Models/Payment.php +++ b/app/Models/Payment.php @@ -2,27 +2,32 @@ namespace App\Models; +use App\Models\Filterable; use App\Utils\Traits\MakesHash; use Illuminate\Database\Eloquent\Model; class Payment extends BaseModel { use MakesHash; + use Filterable; protected $guarded = [ 'id', ]; - protected $appends = ['payment_id']; - - public function getRouteKeyName() + public function client() { - return 'payment_id'; + return $this->belongsTo(Client::class); } - public function getPaymentIdAttribute() + public function company() { - return $this->encodePrimaryKey($this->id); + return $this->belongsTo(Company::class); + } + + public function user() + { + return $this->belongsTo(User::class); } public function documents() diff --git a/app/Models/RecurringInvoice.php b/app/Models/RecurringInvoice.php index b84ce24c719b..f06cbf996ae2 100644 --- a/app/Models/RecurringInvoice.php +++ b/app/Models/RecurringInvoice.php @@ -7,12 +7,41 @@ use App\Utils\Traits\MakesHash; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; +/** + * Class for Recurring Invoices. + */ class RecurringInvoice extends BaseModel { use MakesHash; use SoftDeletes; use Filterable; + /** + * Invoice Statuses + */ + const STATUS_DRAFT = 2; + const STATUS_ACTIVE = 3; + const STATUS_PENDING = -1; + const STATUS_COMPLETED = -2; + const STATUS_CANCELLED = -3; + + + /** + * Recurring intervals + */ + const FREQUENCY_WEEKLY = 1; + const FREQUENCY_TWO_WEEKS = 2; + const FREQUENCY_FOUR_WEEKS = 3; + const FREQUENCY_MONTHLY = 4; + const FREQUENCY_TWO_MONTHS = 5; + const FREQUENCY_THREE_MONTHS = 6; + const FREQUENCY_FOUR_MONTHS = 7; + const FREQUENCY_SIX_MONTHS = 8; + const FREQUENCY_ANNUALLY = 9; + const FREQUENCY_TWO_YEARS = 10; + + const RECURS_INDEFINITELY = 1; + protected $guarded = [ 'id', ]; @@ -21,11 +50,21 @@ class RecurringInvoice extends BaseModel 'settings' => 'object' ]; + protected $with = [ + // 'client', + // 'company', + ]; + public function company() { return $this->belongsTo(Company::class); } + public function client() + { + return $this->belongsTo(Client::class); + } + public function user() { return $this->belongsTo(User::class); diff --git a/app/Policies/PaymentPolicy.php b/app/Policies/PaymentPolicy.php new file mode 100644 index 000000000000..986a60bac533 --- /dev/null +++ b/app/Policies/PaymentPolicy.php @@ -0,0 +1,25 @@ +isAdmin() || $user->hasPermission('create_payment'); + } + +} diff --git a/app/Policies/RecurringInvoicePolicy.php b/app/Policies/RecurringInvoicePolicy.php new file mode 100644 index 000000000000..ab255cce577e --- /dev/null +++ b/app/Policies/RecurringInvoicePolicy.php @@ -0,0 +1,25 @@ +isAdmin() || $user->hasPermission('create_recurring_invoice'); + } + +} diff --git a/app/Providers/AuthServiceProvider.php b/app/Providers/AuthServiceProvider.php index f48b7ba08831..82ca77936732 100644 --- a/app/Providers/AuthServiceProvider.php +++ b/app/Providers/AuthServiceProvider.php @@ -4,13 +4,17 @@ namespace App\Providers; use App\Models\Client; use App\Models\Invoice; +use App\Models\Payment; use App\Models\Product; use App\Models\Quote; +use App\Models\RecurringInvoice; use App\Models\User; use App\Policies\ClientPolicy; use App\Policies\InvoicePolicy; +use App\Policies\PaymentPolicy; use App\Policies\ProductPolicy; use App\Policies\QuotePolicy; +use App\Policies\RecurringInvoicePolicy; use Auth; use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider; use Illuminate\Support\Facades\Gate; @@ -26,6 +30,8 @@ class AuthServiceProvider extends ServiceProvider Client::class => ClientPolicy::class, Product::class => ProductPolicy::class, Invoice::class => InvoicePolicy::class, + Payment::class => PaymentPolicy::class, + RecurringInvoice::class => RecurringInvoicePolicy::class, Quote::class => QuotePolicy::class, User::class => UserPolicy::class, ]; diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index 7547c292e611..674ba882fe43 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -42,6 +42,10 @@ class RouteServiceProvider extends ServiceProvider return \App\Models\Invoice::withTrashed()->where('id', $this->decodePrimaryKey($value))->firstOrFail(); }); + Route::bind('recurring_invoice', function ($value) { + return \App\Models\RecurringInvoice::withTrashed()->where('id', $this->decodePrimaryKey($value))->firstOrFail(); + }); + Route::bind('quote', function ($value) { return \App\Models\Quote::withTrashed()->where('id', $this->decodePrimaryKey($value))->firstOrFail(); }); diff --git a/app/Repositories/PaymentRepository.php b/app/Repositories/PaymentRepository.php new file mode 100644 index 000000000000..63004d332756 --- /dev/null +++ b/app/Repositories/PaymentRepository.php @@ -0,0 +1,29 @@ +fill($request->input()); + + $payment->save(); + + return $payment; + } + +} \ No newline at end of file diff --git a/app/Repositories/RecurringInvoiceRepository.php b/app/Repositories/RecurringInvoiceRepository.php new file mode 100644 index 000000000000..b103ce1f7036 --- /dev/null +++ b/app/Repositories/RecurringInvoiceRepository.php @@ -0,0 +1,38 @@ +fill($request->input()); + + $invoice->save(); + + + $invoice_calc = new InvoiceCalc($invoice, $invoice->settings); + + $invoice = $invoice_calc->build()->getInvoice(); + + //fire events here that cascading from the saving of an invoice + //ie. client balance update... + + return $invoice; + } + +} \ No newline at end of file diff --git a/app/Transformers/RecurringInvoiceTransformer.php b/app/Transformers/RecurringInvoiceTransformer.php new file mode 100644 index 000000000000..e8a668113e07 --- /dev/null +++ b/app/Transformers/RecurringInvoiceTransformer.php @@ -0,0 +1,162 @@ +serializer); + + return $this->includeCollection($invoice->invoice_items, $transformer, ENTITY_INVOICE_ITEM); + } + + public function includeInvitations(Invoice $invoice) + { + $transformer = new InvitationTransformer($this->account, $this->serializer); + + return $this->includeCollection($invoice->invitations, $transformer, ENTITY_INVITATION); + } + + public function includePayments(Invoice $invoice) + { + $transformer = new PaymentTransformer($this->account, $this->serializer, $invoice); + + return $this->includeCollection($invoice->payments, $transformer, ENTITY_PAYMENT); + } + + public function includeClient(Invoice $invoice) + { + $transformer = new ClientTransformer($this->account, $this->serializer); + + return $this->includeItem($invoice->client, $transformer, ENTITY_CLIENT); + } + + public function includeExpenses(Invoice $invoice) + { + $transformer = new ExpenseTransformer($this->account, $this->serializer); + + return $this->includeCollection($invoice->expenses, $transformer, ENTITY_EXPENSE); + } + + public function includeDocuments(Invoice $invoice) + { + $transformer = new DocumentTransformer($this->account, $this->serializer); + + $invoice->documents->each(function ($document) use ($invoice) { + $document->setRelation('invoice', $invoice); + }); + + return $this->includeCollection($invoice->documents, $transformer, ENTITY_DOCUMENT); + } +*/ + public function transform(RecurringInvoice $invoice) + { + return [ + 'id' => $this->encodePrimaryKey($invoice->id), + 'amount' => (float) $invoice->amount, + 'balance' => (float) $invoice->balance, + 'client_id' => (int) $invoice->client_id, + 'status_id' => (int) ($invoice->status_id ?: 1), + 'updated_at' => $invoice->updated_at, + 'archived_at' => $invoice->deleted_at, + 'discount' => (float) $invoice->discount, + 'po_number' => $invoice->po_number, + 'invoice_date' => $invoice->invoice_date ?: '', + 'due_date' => $invoice->due_date ?: '', + 'terms' => $invoice->terms ?: '', + 'public_notes' => $invoice->public_notes ?: '', + 'private_notes' => $invoice->private_notes ?: '', + 'is_deleted' => (bool) $invoice->is_deleted, + 'tax_name1' => $invoice->tax_name1 ? $invoice->tax_name1 : '', + 'tax_rate1' => (float) $invoice->tax_rate1, + 'tax_name2' => $invoice->tax_name2 ? $invoice->tax_name2 : '', + 'tax_rate2' => (float) $invoice->tax_rate2, + 'is_amount_discount' => (bool) ($invoice->is_amount_discount ?: false), + 'invoice_footer' => $invoice->invoice_footer ?: '', + 'partial' => (float) ($invoice->partial ?: 0.0), + 'partial_due_date' => $invoice->partial_due_date ?: '', + 'custom_value1' => (float) $invoice->custom_value1, + 'custom_value2' => (float) $invoice->custom_value2, + 'custom_taxes1' => (bool) $invoice->custom_taxes1, + 'custom_taxes2' => (bool) $invoice->custom_taxes2, + 'has_tasks' => (bool) $invoice->has_tasks, + 'has_expenses' => (bool) $invoice->has_expenses, + 'custom_text_value1' => $invoice->custom_text_value1 ?: '', + 'custom_text_value2' => $invoice->custom_text_value2 ?: '', + 'backup' => $invoice->backup ?: '', + 'settings' => $invoice->settings, + 'frequency_id' => (int) $invoice->frequency_id, + 'start_date' => $invoice->start_date, + 'last_sent_date' => $invoice->last_sent_date, + 'next_send_date' => $invoice->next_send_date, + 'remaining_cycles' => (int) $invoice->remaining_cycles, + ]; + } +} diff --git a/database/factories/PaymentFactory.php b/database/factories/PaymentFactory.php new file mode 100644 index 000000000000..de107b6e2eb9 --- /dev/null +++ b/database/factories/PaymentFactory.php @@ -0,0 +1,17 @@ +define(App\Models\Payment::class, function (Faker $faker) { + return [ + 'is_deleted' => false, + 'amount' => $faker->numberBetween(1,10), + 'payment_date' => $faker->date(), + 'transaction_reference' => $faker->text(10), + 'invoice_id' => $faker->numberBetween(1,10) + ]; +}); + + \ No newline at end of file diff --git a/database/factories/RecurringInvoiceFactory.php b/database/factories/RecurringInvoiceFactory.php new file mode 100644 index 000000000000..cb735c181f8c --- /dev/null +++ b/database/factories/RecurringInvoiceFactory.php @@ -0,0 +1,32 @@ +define(App\Models\RecurringInvoice::class, function (Faker $faker) { + return [ + 'status_id' => App\Models\RecurringInvoice::STATUS_PENDING, + 'discount' => $faker->numberBetween(1,10), + 'is_amount_discount' => $faker->boolean(), + 'tax_name1' => 'GST', + 'tax_rate1' => 10, + 'tax_name2' => 'VAT', + 'tax_rate2' => 17.5, + 'custom_value1' => $faker->numberBetween(1,4), + 'custom_value2' => $faker->numberBetween(1,4), + 'custom_value3' => $faker->numberBetween(1,4), + 'custom_value4' => $faker->numberBetween(1,4), + 'is_deleted' => false, + 'po_number' => $faker->text(10), + 'invoice_date' => $faker->date(), + 'due_date' => $faker->date(), + 'line_items' => false, + 'backup' => '', + 'frequency_id' => App\Models\RecurringInvoice::FREQUENCY_MONTHLY, + 'start_date' => $faker->date(), + 'last_sent_date' => $faker->date(), + 'next_send_date' => $faker->date(), + 'remaining_cycles' => $faker->numberBetween(1,10), + ]; +}); \ No newline at end of file diff --git a/database/migrations/2014_10_13_000000_create_users_table.php b/database/migrations/2014_10_13_000000_create_users_table.php index 71145e854616..984cdf54d0b4 100644 --- a/database/migrations/2014_10_13_000000_create_users_table.php +++ b/database/migrations/2014_10_13_000000_create_users_table.php @@ -418,7 +418,8 @@ class CreateUsersTable extends Migration $t->unsignedInteger('user_id'); $t->unsignedInteger('company_id')->index(); - $t->string('invoice_number'); + $t->unsignedInteger('status_id')->index(); + $t->float('discount'); $t->boolean('is_amount_discount'); @@ -469,7 +470,6 @@ class CreateUsersTable extends Migration $t->timestamps(); $t->softDeletes(); - $t->unique(['company_id', 'invoice_number']); }); Schema::create('quotes', function ($t) { @@ -624,7 +624,7 @@ class CreateUsersTable extends Migration $t->string('transaction_reference')->nullable(); $t->string('payer_id')->nullable(); - $t->foreign('invoice_id')->references('id')->on('invoices')->onDelete('cascade'); + //$t->foreign('invoice_id')->references('id')->on('invoices')->onDelete('cascade'); $t->foreign('company_id')->references('id')->on('companies')->onDelete('cascade'); $t->foreign('client_id')->references('id')->on('clients')->onDelete('cascade'); $t->foreign('client_contact_id')->references('id')->on('client_contacts')->onDelete('cascade'); diff --git a/routes/api.php b/routes/api.php index 6109501d69e8..84bfd75bf191 100644 --- a/routes/api.php +++ b/routes/api.php @@ -51,14 +51,16 @@ Route::group(['middleware' => ['db','api_secret_check','token_auth'], 'prefix' = Route::post('recurring_invoices/bulk', 'RecurringInvoiceController@bulk')->name('recurring_invoices.bulk'); Route::resource('client_statement', 'ClientStatementController@statement'); // name = (client_statement. index / create / show / update / destroy / edit + + Route::resource('payments', 'PaymentController'); // name = (payments. index / create / show / update / destroy / edit + + Route::post('payments/bulk', 'PaymentController@bulk')->name('payments.bulk'); + /* Route::resource('tasks', 'TaskController'); // name = (tasks. index / create / show / update / destroy / edit Route::post('tasks/bulk', 'TaskController@bulk')->name('tasks.bulk'); - Route::resource('payments', 'PaymentController'); // name = (payments. index / create / show / update / destroy / edit - - Route::post('payments/bulk', 'PaymentController@bulk')->name('payments.bulk'); Route::resource('credits', 'CreditController'); // name = (credits. index / create / show / update / destroy / edit diff --git a/tests/Feature/PaymentTest.php b/tests/Feature/PaymentTest.php new file mode 100644 index 000000000000..32d8545962b8 --- /dev/null +++ b/tests/Feature/PaymentTest.php @@ -0,0 +1,198 @@ +faker = \Faker\Factory::create(); + + Model::reguard(); + + + } + + public function testPaymentList() + { + $data = [ + 'first_name' => $this->faker->firstName, + 'last_name' => $this->faker->lastName, + 'email' => $this->faker->unique()->safeEmail, + 'password' => 'ALongAndBrilliantPassword123', + '_token' => csrf_token(), + 'privacy_policy' => 1, + 'terms_of_service' => 1 + ]; + + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + ])->post('/api/v1/signup', $data); + + $acc = $response->json(); + + $account = Account::find($this->decodePrimaryKey($acc['data']['id'])); + + $company_token = $account->default_company->tokens()->first(); + $token = $company_token->token; + $company = $company_token->company; + + $user = $company_token->user; + + $this->assertNotNull($company_token); + $this->assertNotNull($token); + $this->assertNotNull($user); + $this->assertNotNull($company); + $this->assertNotNull($user->tokens->first()->company); + + factory(\App\Models\Client::class, 1)->create(['user_id' => $user->id, 'company_id' => $company->id])->each(function ($c) use ($user, $company){ + + factory(\App\Models\ClientContact::class,1)->create([ + 'user_id' => $user->id, + 'client_id' => $c->id, + 'company_id' => $company->id, + 'is_primary' => 1 + ]); + + factory(\App\Models\ClientContact::class,1)->create([ + 'user_id' => $user->id, + 'client_id' => $c->id, + 'company_id' => $company->id + ]); + + }); + $client = Client::all()->first(); + + factory(\App\Models\Payment::class, 1)->create(['user_id' => $user->id, 'company_id' => $company->id, 'client_id' => $client->id]); + + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $token, + ])->get('/api/v1/payments'); + + $response->assertStatus(200); + + } + + public function testPaymentRESTEndPoints() + { + $data = [ + 'first_name' => $this->faker->firstName, + 'last_name' => $this->faker->lastName, + 'email' => $this->faker->unique()->safeEmail, + 'password' => 'ALongAndBrilliantPassword123', + '_token' => csrf_token(), + 'privacy_policy' => 1, + 'terms_of_service' => 1 + ]; + + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + ])->post('/api/v1/signup', $data); + + $acc = $response->json(); + + $account = Account::find($this->decodePrimaryKey($acc['data']['id'])); + + $company_token = $account->default_company->tokens()->first(); + $token = $company_token->token; + $company = $company_token->company; + + $user = $company_token->user; + + $this->assertNotNull($company_token); + $this->assertNotNull($token); + $this->assertNotNull($user); + $this->assertNotNull($company); + $this->assertNotNull($user->tokens->first()->company); + + factory(\App\Models\Client::class, 1)->create(['user_id' => $user->id, 'company_id' => $company->id])->each(function ($c) use ($user, $company){ + + factory(\App\Models\ClientContact::class,1)->create([ + 'user_id' => $user->id, + 'client_id' => $c->id, + 'company_id' => $company->id, + 'is_primary' => 1 + ]); + + factory(\App\Models\ClientContact::class,1)->create([ + 'user_id' => $user->id, + 'client_id' => $c->id, + 'company_id' => $company->id + ]); + + }); + $client = Client::all()->first(); + + factory(\App\Models\Payment::class, 1)->create(['user_id' => $user->id, 'company_id' => $company->id, 'client_id' => $client->id]); + + $Payment = Payment::all()->first(); + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $token, + ])->get('/api/v1/payments/'.$this->encodePrimaryKey($Payment->id)); + + $response->assertStatus(200); + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $token, + ])->get('/api/v1/payments/'.$this->encodePrimaryKey($Payment->id).'/edit'); + + $response->assertStatus(200); + + $Payment_update = [ + 'amount' => 10 + ]; + + $this->assertNotNull($Payment); + + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $token, + ])->put('/api/v1/payments/'.$this->encodePrimaryKey($Payment->id), $Payment_update) + ->assertStatus(200); + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $token, + ])->delete('/api/v1/payments/'.$this->encodePrimaryKey($Payment->id)); + + $response->assertStatus(200); + + } + +} diff --git a/tests/Feature/QuoteTest.php b/tests/Feature/QuoteTest.php index 834dd56e018c..b8224d4dfc7c 100644 --- a/tests/Feature/QuoteTest.php +++ b/tests/Feature/QuoteTest.php @@ -160,7 +160,7 @@ class QuoteTest extends TestCase $quote = Quote::where('user_id',$user->id)->first(); $quote->settings = $client->getMergedSettings(); $quote->save(); - Log::error(print_r($quote,1)); + $response = $this->withHeaders([ 'X-API-SECRET' => config('ninja.api_secret'), 'X-API-TOKEN' => $token, diff --git a/tests/Feature/RecurringInvoiceTest.php b/tests/Feature/RecurringInvoiceTest.php new file mode 100644 index 000000000000..abc4eb0e51c2 --- /dev/null +++ b/tests/Feature/RecurringInvoiceTest.php @@ -0,0 +1,203 @@ +faker = \Faker\Factory::create(); + + Model::reguard(); + + + } + + public function testRecurringInvoiceList() + { + $data = [ + 'first_name' => $this->faker->firstName, + 'last_name' => $this->faker->lastName, + 'email' => $this->faker->unique()->safeEmail, + 'password' => 'ALongAndBrilliantPassword123', + '_token' => csrf_token(), + 'privacy_policy' => 1, + 'terms_of_service' => 1 + ]; + + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + ])->post('/api/v1/signup', $data); + + $acc = $response->json(); + + $account = Account::find($this->decodePrimaryKey($acc['data']['id'])); + + $company_token = $account->default_company->tokens()->first(); + $token = $company_token->token; + $company = $company_token->company; + + $user = $company_token->user; + + $this->assertNotNull($company_token); + $this->assertNotNull($token); + $this->assertNotNull($user); + $this->assertNotNull($company); + $this->assertNotNull($user->tokens->first()->company); + + factory(\App\Models\Client::class, 1)->create(['user_id' => $user->id, 'company_id' => $company->id])->each(function ($c) use ($user, $company){ + + factory(\App\Models\ClientContact::class,1)->create([ + 'user_id' => $user->id, + 'client_id' => $c->id, + 'company_id' => $company->id, + 'is_primary' => 1 + ]); + + factory(\App\Models\ClientContact::class,1)->create([ + 'user_id' => $user->id, + 'client_id' => $c->id, + 'company_id' => $company->id + ]); + + }); + $client = Client::all()->first(); + + factory(\App\Models\RecurringInvoice::class, 1)->create(['user_id' => $user->id, 'company_id' => $company->id, 'client_id' => $client->id]); + + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $token, + ])->get('/api/v1/recurring_invoices'); + + $response->assertStatus(200); + + } + + public function testRecurringInvoiceRESTEndPoints() + { + $data = [ + 'first_name' => $this->faker->firstName, + 'last_name' => $this->faker->lastName, + 'email' => $this->faker->unique()->safeEmail, + 'password' => 'ALongAndBrilliantPassword123', + '_token' => csrf_token(), + 'privacy_policy' => 1, + 'terms_of_service' => 1 + ]; + + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + ])->post('/api/v1/signup', $data); + + $acc = $response->json(); + + $account = Account::find($this->decodePrimaryKey($acc['data']['id'])); + + $company_token = $account->default_company->tokens()->first(); + $token = $company_token->token; + $company = $company_token->company; + + $user = $company_token->user; + + $this->assertNotNull($company_token); + $this->assertNotNull($token); + $this->assertNotNull($user); + $this->assertNotNull($company); + $this->assertNotNull($user->tokens->first()->company); + + factory(\App\Models\Client::class, 1)->create(['user_id' => $user->id, 'company_id' => $company->id])->each(function ($c) use ($user, $company){ + + factory(\App\Models\ClientContact::class,1)->create([ + 'user_id' => $user->id, + 'client_id' => $c->id, + 'company_id' => $company->id, + 'is_primary' => 1 + ]); + + factory(\App\Models\ClientContact::class,1)->create([ + 'user_id' => $user->id, + 'client_id' => $c->id, + 'company_id' => $company->id + ]); + + }); + $client = Client::all()->first(); + + factory(\App\Models\RecurringInvoice::class, 1)->create(['user_id' => $user->id, 'company_id' => $company->id, 'client_id' => $client->id]); + + $RecurringInvoice = RecurringInvoice::where('user_id',$user->id)->first(); + $RecurringInvoice->settings = $client->getMergedSettings(); + $RecurringInvoice->save(); + + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $token, + ])->get('/api/v1/recurring_invoices/'.$this->encodePrimaryKey($RecurringInvoice->id)); + + $response->assertStatus(200); + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $token, + ])->get('/api/v1/recurring_invoices/'.$this->encodePrimaryKey($RecurringInvoice->id).'/edit'); + + $response->assertStatus(200); + + $RecurringInvoice_update = [ + 'status_id' => RecurringInvoice::STATUS_DRAFT + ]; + + $this->assertNotNull($RecurringInvoice); + $this->assertNotNull($RecurringInvoice->settings); + + $this->assertTrue(property_exists($RecurringInvoice->settings, 'custom_taxes1')); + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $token, + ])->put('/api/v1/recurring_invoices/'.$this->encodePrimaryKey($RecurringInvoice->id), $RecurringInvoice_update) + ->assertStatus(200); + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $token, + ])->delete('/api/v1/recurring_invoices/'.$this->encodePrimaryKey($RecurringInvoice->id)); + + $response->assertStatus(200); + + } + +} diff --git a/tests/Unit/FactoryCreationTest.php b/tests/Unit/FactoryCreationTest.php index 97a390b6ccf7..8a40cc9112ba 100644 --- a/tests/Unit/FactoryCreationTest.php +++ b/tests/Unit/FactoryCreationTest.php @@ -85,7 +85,7 @@ class FactoryCreationTest extends TestCase /** * @test - * @covers App|Factory\CloneInvoiceFactory + * @covers App\Factory\CloneInvoiceFactory */ public function testCloneInvoiceCreation() { @@ -114,7 +114,7 @@ class FactoryCreationTest extends TestCase /** * @test - * @covers App|Factory\ClientFactory + * @covers App\Factory\ClientFactory */ public function testClientCreate() { @@ -129,7 +129,7 @@ class FactoryCreationTest extends TestCase /** * @test - * @covers App|Factory\ClientContactFactory + * @covers App\Factory\ClientContactFactory */ public function testClientContactCreate() { @@ -166,7 +166,7 @@ class FactoryCreationTest extends TestCase /** * @test - * @covers App|Factory\UserFactory + * @covers App\Factory\UserFactory */ public function testUserCreate() {