mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
commit
5c81a40461
37
app/Events/Credit/CreditWasViewed.php
Normal file
37
app/Events/Credit/CreditWasViewed.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com)
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
|
||||
namespace App\Events\Credit;
|
||||
|
||||
use App\Models\Company;
|
||||
use App\Models\CreditWasViewed;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
/**
|
||||
* Class CreditWasViewed.
|
||||
*/
|
||||
class CreditWasViewed
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
public $invitation;
|
||||
|
||||
public $company;
|
||||
|
||||
public $event_vars;
|
||||
|
||||
public function __construct(CreditInvitation $invitation, Company $company, array $event_vars)
|
||||
{
|
||||
$this->invitation = $invitation;
|
||||
$this->company = $company;
|
||||
$this->event_vars = $event_vars;
|
||||
}
|
||||
}
|
@ -126,7 +126,7 @@ class Handler extends ExceptionHandler
|
||||
return response()->json(['message' => $exception->getMessage()], 400);
|
||||
} elseif ($exception instanceof GenericPaymentDriverFailure) {
|
||||
$data['message'] = $exception->getMessage();
|
||||
dd($data);
|
||||
//dd($data);
|
||||
// return view('errors.layout', $data);
|
||||
}
|
||||
|
||||
|
@ -11,12 +11,16 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Requests\Activity\DownloadHistoricalEntityRequest;
|
||||
use App\Models\Activity;
|
||||
use App\Transformers\ActivityTransformer;
|
||||
use App\Utils\Traits\Pdf\PdfMaker;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ActivityController extends BaseController
|
||||
{
|
||||
use PdfMaker;
|
||||
|
||||
protected $entity_type = Activity::class;
|
||||
|
||||
protected $entity_transformer = ActivityTransformer::class;
|
||||
@ -78,7 +82,70 @@ class ActivityController extends BaseController
|
||||
$activities = Activity::orderBy('created_at', 'DESC')->company()
|
||||
->take($default_activities);
|
||||
|
||||
|
||||
return $this->listResponse($activities);
|
||||
}
|
||||
|
||||
/**
|
||||
* @OA\Get(
|
||||
* path="/api/v1/actvities/download_entity/{activity_id}",
|
||||
* operationId="getActivityHistoricalEntityPdf",
|
||||
* tags={"actvities"},
|
||||
* summary="Gets a PDF for the given activity",
|
||||
* description="Gets a PDF for the given activity",
|
||||
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
||||
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
|
||||
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||
* @OA\Parameter(
|
||||
* name="activity_id",
|
||||
* in="path",
|
||||
* description="The Activity Hashed ID",
|
||||
* example="D2J234DFA",
|
||||
* required=true,
|
||||
* @OA\Schema(
|
||||
* type="string",
|
||||
* format="string",
|
||||
* ),
|
||||
* ),
|
||||
* @OA\Response(
|
||||
* response=200,
|
||||
* description="PDF File",
|
||||
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
|
||||
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
|
||||
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
|
||||
* ),
|
||||
* @OA\Response(
|
||||
* response=404,
|
||||
* description="No file exists for the given record",
|
||||
* ),
|
||||
* @OA\Response(
|
||||
* response="default",
|
||||
* description="Unexpected Error",
|
||||
* @OA\JsonContent(ref="#/components/schemas/Error"),
|
||||
* ),
|
||||
* )
|
||||
*
|
||||
*/
|
||||
public function downloadHistoricalEntity(DownloadHistoricalEntityRequest $request, Activity $activity)
|
||||
{
|
||||
$backup = $activity->backup;
|
||||
|
||||
if(!$backup || !$backup->html_backup)
|
||||
return response()->json(['message'=> 'No backup exists for this activity', 'errors' => new \stdClass], 404);
|
||||
|
||||
$pdf = $this->makePdf(null, null, $backup->html_backup);
|
||||
|
||||
if(isset($activity->invoice_id))
|
||||
$filename = $activity->invoice->number . ".pdf";
|
||||
elseif(isset($activity->quote_id))
|
||||
$filename = $activity->quote->number . ".pdf";
|
||||
elseif(isset($activity->credit_id))
|
||||
$filename = $activity->credit->number . ".pdf";
|
||||
else
|
||||
$filename = "backup.pdf";
|
||||
|
||||
return response()->streamDownload(function () use($pdf) {
|
||||
echo $pdf;
|
||||
}, $filename);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -68,6 +68,7 @@ class BaseController extends Controller
|
||||
'company.groups',
|
||||
'company.company_gateways.gateway',
|
||||
'company.clients.contacts',
|
||||
'company.clients.gateway_tokens',
|
||||
'company.products',
|
||||
'company.invoices.invitations.contact',
|
||||
'company.invoices.invitations.company',
|
||||
|
@ -49,7 +49,7 @@ class DocumentController extends Controller
|
||||
{
|
||||
$contact = auth()->user();
|
||||
|
||||
Storage::makeDirectory('public/' . $contact->client->client_hash, 0755);
|
||||
Storage::makeDirectory('public/' . $contact->client->client_hash, 0775);
|
||||
|
||||
$path = Storage::putFile('public/' . $contact->client->client_hash, $request->file('file'));
|
||||
|
||||
|
@ -11,8 +11,10 @@
|
||||
|
||||
namespace App\Http\Controllers\ClientPortal;
|
||||
|
||||
use App\Events\Credit\CreditWasViewed;
|
||||
use App\Events\Invoice\InvoiceWasViewed;
|
||||
use App\Events\Misc\InvitationWasViewed;
|
||||
use App\Events\Quote\QuoteWasViewed;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\InvoiceInvitation;
|
||||
use App\Utils\Ninja;
|
||||
@ -70,7 +72,12 @@ class InvitationController extends Controller
|
||||
case 'invoice':
|
||||
event(new InvoiceWasViewed($invitation, $invitation->company, Ninja::eventVars()));
|
||||
break;
|
||||
|
||||
case 'quote':
|
||||
event(new QuoteWasViewed($invitation, $invitation->company, Ninja::eventVars()));
|
||||
break;
|
||||
case 'credit':
|
||||
event(new CreditWasViewed($invitation, $invitation->company, Ninja::eventVars()));
|
||||
break;
|
||||
default:
|
||||
# code...
|
||||
break;
|
||||
|
@ -495,8 +495,82 @@ class CompanyController extends BaseController
|
||||
}
|
||||
}
|
||||
|
||||
// ob_flush();
|
||||
|
||||
return response()->json(['message' => 'success'], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Purge Company
|
||||
*
|
||||
* @OA\Post(
|
||||
* path="/api/v1/companies/purge/{company}",
|
||||
* operationId="postCompanyPurge",
|
||||
* tags={"companies"},
|
||||
* summary="Attempts to purge a company record and all its child records",
|
||||
* description="Attempts to purge a company record and all its child records",
|
||||
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
||||
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
|
||||
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||
* @OA\Parameter(
|
||||
* name="company",
|
||||
* in="path",
|
||||
* description="The Company Hashed ID",
|
||||
* example="D2J234DFA",
|
||||
* required=true,
|
||||
* @OA\Schema(
|
||||
* type="string",
|
||||
* format="string",
|
||||
* ),
|
||||
* ),
|
||||
* @OA\Response(
|
||||
* response=200,
|
||||
* description="Returns a refresh object",
|
||||
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
|
||||
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
|
||||
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
|
||||
* @OA\JsonContent(ref="#/components/schemas/CompanyUser"),
|
||||
* ),
|
||||
* @OA\Response(
|
||||
* response=422,
|
||||
* description="Validation error",
|
||||
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
|
||||
* ),
|
||||
* @OA\Response(
|
||||
* response="default",
|
||||
* description="Unexpected Error",
|
||||
* @OA\JsonContent(ref="#/components/schemas/Error"),
|
||||
* ),
|
||||
* )
|
||||
*/
|
||||
public function purgeCompany(Company $company)
|
||||
{
|
||||
$account = $company->account;
|
||||
$company_id = $company->id;
|
||||
|
||||
$company->delete();
|
||||
|
||||
/*Set New Company*/
|
||||
if($account->companies->count() >= 1)
|
||||
auth()->user()->setCompany($account->companies->first());
|
||||
|
||||
/*Update the new default company if necessary*/
|
||||
if($company_id == $account->default_company_id){
|
||||
|
||||
$new_default_company = $account->companies->first();
|
||||
|
||||
if($new_default_company){
|
||||
$account->default_company_id = $new_default_company->id;
|
||||
$account->save();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*Prep response*/
|
||||
$this->entity_type = CompanyUser::class;
|
||||
$this->entity_transformer = CompanyUserTransformer::class;
|
||||
|
||||
$company_user = $account->company_users->where('user_id', auth()->user()->id);
|
||||
|
||||
return $this->refreshResponse($company_user);
|
||||
}
|
||||
}
|
||||
|
@ -725,10 +725,6 @@ class InvoiceController extends BaseController
|
||||
|
||||
});
|
||||
|
||||
if ($invoice->invitations->count() > 0) {
|
||||
event(new InvoiceWasEmailed($invoice->invitations->first(), $invoice->company, Ninja::eventVars()));
|
||||
}
|
||||
|
||||
if (!$bulk) {
|
||||
return response()->json(['message' => 'email sent'], 200);
|
||||
}
|
||||
|
@ -77,18 +77,7 @@ class MigrationController extends BaseController
|
||||
*/
|
||||
public function purgeCompany(Company $company)
|
||||
{
|
||||
// $account = $company->account;
|
||||
|
||||
// if($account->default_company_id == $company->id)
|
||||
// {
|
||||
// $companies = $account->companies;
|
||||
|
||||
// if($companies->count() > 1)
|
||||
// {
|
||||
|
||||
|
||||
// }
|
||||
// }
|
||||
$company->delete();
|
||||
|
||||
return response()->json(['message' => 'Company purged'], 200);
|
||||
|
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com)
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
|
||||
namespace App\Http\Requests\Activity;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use App\Models\Activity;
|
||||
|
||||
class DownloadHistoricalEntityRequest extends Request
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
|
||||
public function authorize() : bool
|
||||
{
|
||||
return auth()->user()->can('view', $this->activity);
|
||||
}
|
||||
}
|
@ -54,6 +54,9 @@ class UpdateInvoiceRequest extends Request
|
||||
|
||||
$rules['id'] = new LockedInvoiceRule($this->invoice);
|
||||
|
||||
if($this->input('number'))
|
||||
$rules['number'] = 'unique:invoices,number,' . $this->id . ',id,company_id,' . $this->invoice->company_id;
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
|
@ -60,7 +60,7 @@ class UniqueInvoiceNumberRule implements Rule
|
||||
$invoice = Invoice::where('client_id', $this->input['client_id'])
|
||||
->where('number', $this->input['number'])
|
||||
->withTrashed()
|
||||
->first();
|
||||
->exists();
|
||||
|
||||
if($invoice)
|
||||
return false;
|
||||
|
@ -87,7 +87,7 @@ class CreateCreditPdf implements ShouldQueue
|
||||
|
||||
$html = (new HtmlEngine($designer, $this->invitation, 'credit'))->build();
|
||||
|
||||
Storage::makeDirectory($path, 0755);
|
||||
Storage::makeDirectory($path, 0775);
|
||||
|
||||
$pdf = $this->makePdf(null, null, $html);
|
||||
|
||||
|
@ -86,7 +86,7 @@ class CreateInvoicePdf implements ShouldQueue
|
||||
$html = (new HtmlEngine($designer, $this->invitation, 'invoice'))->build();
|
||||
|
||||
//todo - move this to the client creation stage so we don't keep hitting this unnecessarily
|
||||
Storage::makeDirectory($path, 0755);
|
||||
Storage::makeDirectory($path, 0775);
|
||||
|
||||
$pdf = $this->makePdf(null, null, $html);
|
||||
|
||||
|
@ -22,6 +22,7 @@ use App\Models\Company;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\InvoiceInvitation;
|
||||
use App\Models\SystemLog;
|
||||
use App\Utils\Ninja;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
@ -75,18 +76,30 @@ class EmailInvoice extends BaseMailerJob implements ShouldQueue
|
||||
|
||||
$this->setMailDriver();
|
||||
|
||||
Mail::to($this->invoice_invitation->contact->email, $this->invoice_invitation->contact->present()->name())
|
||||
->send(
|
||||
new TemplateEmail(
|
||||
$this->email_builder,
|
||||
$this->invoice_invitation->contact->user,
|
||||
$this->invoice_invitation->contact->client
|
||||
)
|
||||
);
|
||||
try {
|
||||
|
||||
Mail::to($this->invoice_invitation->contact->email, $this->invoice_invitation->contact->present()->name())
|
||||
->send(
|
||||
new TemplateEmail(
|
||||
$this->email_builder,
|
||||
$this->invoice_invitation->contact->user,
|
||||
$this->invoice_invitation->contact->client
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
catch (\Swift_TransportException $e) {
|
||||
|
||||
event(new InvoiceWasEmailedAndFailed($this->invoice_invitation->invoice, $this->company, $e->getMessage(), Ninja::eventVars()));
|
||||
}
|
||||
|
||||
if (count(Mail::failures()) > 0) {
|
||||
return $this->logMailError(Mail::failures(), $this->invoice->client);
|
||||
}
|
||||
else{
|
||||
event(new InvoiceWasEmailed($this->invoice_invitation, $this->company, Ninja::eventVars()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -84,7 +84,7 @@ class CreateQuotePdf implements ShouldQueue
|
||||
$designer = new Designer($this->quote, $design, $this->quote->client->getSetting('pdf_variables'), 'quote');
|
||||
|
||||
//todo - move this to the client creation stage so we don't keep hitting this unnecessarily
|
||||
Storage::makeDirectory($path, 0755);
|
||||
Storage::makeDirectory($path, 0775);
|
||||
|
||||
$html = (new HtmlEngine($designer, $this->invitation, 'quote'))->build();
|
||||
|
||||
|
@ -39,7 +39,7 @@ class UploadAvatar implements ShouldQueue
|
||||
{
|
||||
|
||||
//make dir
|
||||
Storage::makeDirectory('public/' . $this->directory, 0755);
|
||||
Storage::makeDirectory('public/' . $this->directory, 0775);
|
||||
|
||||
$tmp_file = sha1(time()).".png";
|
||||
|
||||
|
@ -55,13 +55,14 @@ class PaymentCreatedActivity implements ShouldQueue
|
||||
$fields->company_id = $payment->company_id;
|
||||
$fields->activity_type_id = Activity::CREATE_PAYMENT;
|
||||
|
||||
foreach ($invoices as $invoice) { //todo we may need to add additional logic if in the future we apply payments to other entity Types, not just invoices
|
||||
$fields->invoice_id = $invoice->id;
|
||||
/*todo tests fail for this for some reason?*/
|
||||
// foreach ($invoices as $invoice) { //todo we may need to add additional logic if in the future we apply payments to other entity Types, not just invoices
|
||||
// $fields->invoice_id = $invoice->id;
|
||||
|
||||
InvoiceWorkflowSettings::dispatchNow($invoice);
|
||||
// InvoiceWorkflowSettings::dispatchNow($invoice);
|
||||
|
||||
$this->activity_repo->save($fields, $invoice, $event->event_vars);
|
||||
}
|
||||
// $this->activity_repo->save($fields, $invoice, $event->event_vars);
|
||||
// }
|
||||
|
||||
if (count($invoices) == 0) {
|
||||
$this->activity_repo->save($fields, $payment, $event->event_vars);
|
||||
|
59
app/Listeners/Credit/CreditViewedActivity.php
Normal file
59
app/Listeners/Credit/CreditViewedActivity.php
Normal file
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
/**
|
||||
* Credit Ninja (https://creditninja.com)
|
||||
*
|
||||
* @link https://github.com/creditninja/creditninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2020. Credit Ninja LLC (https://creditninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
|
||||
namespace App\Listeners\Credit;
|
||||
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\Activity;
|
||||
use App\Models\ClientContact;
|
||||
use App\Models\CreditInvitation;
|
||||
use App\Repositories\ActivityRepository;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class CreditViewedActivity implements ShouldQueue
|
||||
{
|
||||
protected $activity_repo;
|
||||
/**
|
||||
* Create the event listener.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(ActivityRepository $activity_repo)
|
||||
{
|
||||
$this->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->user_id = $event->invitation->user_id;
|
||||
$fields->company_id = $event->invitation->company_id;
|
||||
$fields->activity_type_id = Activity::VIEW_CREDIT;
|
||||
$fields->client_id = $event->invitation->credit->client_id;
|
||||
$fields->client_contact_id = $event->invitation->client_contact_id;
|
||||
$fields->invitation_id = $event->invitation->id;
|
||||
$fields->credit_id = $event->invitation->credit_id;
|
||||
|
||||
$this->activity_repo->save($fields, $event->invitation->credit, $event->event_vars);
|
||||
}
|
||||
}
|
@ -47,10 +47,11 @@ class InvoiceEmailFailedActivity implements ShouldQueue
|
||||
$fields = new \stdClass;
|
||||
|
||||
$fields->invoice_id = $event->invoice->id;
|
||||
$fields->client_id = $event->invoice->client_id;
|
||||
$fields->user_id = $event->invoice->user_id;
|
||||
$fields->client_id = $event->invoice->client_id;
|
||||
$fields->user_id = $event->invoice->user_id;
|
||||
$fields->company_id = $event->invoice->company_id;
|
||||
$fields->activity_type_id = Activity::EMAIL_INVOICE_FAILED;
|
||||
$fields->notes = $event->errors;
|
||||
|
||||
$this->activity_repo->save($fields, $event->invoice, $event->event_vars);
|
||||
}
|
||||
|
@ -13,11 +13,15 @@ namespace App\Listeners\Invoice;
|
||||
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\Activity;
|
||||
use App\Models\ClientContact;
|
||||
use App\Models\InvoiceInvitation;
|
||||
use App\Repositories\ActivityRepository;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class CreateInvoiceHtmlBackup implements ShouldQueue
|
||||
class InvoicePaidActivity implements ShouldQueue
|
||||
{
|
||||
protected $activity_repo;
|
||||
/**
|
||||
@ -38,15 +42,14 @@ class CreateInvoiceHtmlBackup implements ShouldQueue
|
||||
*/
|
||||
public function handle($event)
|
||||
{
|
||||
MultiDB::setDB($event->company->db);
|
||||
MultiDB::setDb($event->company->db);
|
||||
|
||||
$fields = new \stdClass;
|
||||
|
||||
$fields->invoice_id = $event->invoice->id;
|
||||
$fields->client_id = $event->invoice->client_id;
|
||||
$fields->user_id = $event->invoice->user_id;
|
||||
$fields->user_id = $event->invoice->user_id;
|
||||
$fields->company_id = $event->invoice->company_id;
|
||||
$fields->activity_type_id = Activity::MARK_SENT_INVOICE;
|
||||
$fields->activity_type_id = Activity::PAID_INVOICE;
|
||||
|
||||
$this->activity_repo->save($fields, $event->invoice, $event->event_vars);
|
||||
}
|
@ -11,10 +11,14 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Activity extends StaticModel
|
||||
{
|
||||
|
||||
use MakesHash;
|
||||
|
||||
const CREATE_CLIENT=1; //
|
||||
const ARCHIVE_CLIENT=2; //
|
||||
const DELETE_CLIENT=3; //
|
||||
@ -52,8 +56,9 @@ class Activity extends StaticModel
|
||||
const ARCHIVE_EXPENSE=35;
|
||||
const DELETE_EXPENSE=36;
|
||||
const RESTORE_EXPENSE=37;
|
||||
const VOIDED_PAYMENT=39;
|
||||
const REFUNDED_PAYMENT=40;
|
||||
|
||||
const VOIDED_PAYMENT=39; //
|
||||
const REFUNDED_PAYMENT=40; //
|
||||
const FAILED_PAYMENT=41;
|
||||
const CREATE_TASK=42;
|
||||
const UPDATE_TASK=43;
|
||||
@ -61,17 +66,19 @@ class Activity extends StaticModel
|
||||
const DELETE_TASK=45;
|
||||
const RESTORE_TASK=46;
|
||||
const UPDATE_EXPENSE=47;
|
||||
const CREATE_USER=48;
|
||||
const UPDATE_USER=49;
|
||||
const ARCHIVE_USER=50;
|
||||
const DELETE_USER=51;
|
||||
const RESTORE_USER=52;
|
||||
const MARK_SENT_INVOICE=53;
|
||||
const PAID_INVOICE=54;
|
||||
|
||||
const CREATE_USER=48; // only used in CreateUser::job
|
||||
const UPDATE_USER=49; // not needed?
|
||||
const ARCHIVE_USER=50; // not needed?
|
||||
const DELETE_USER=51; // not needed?
|
||||
const RESTORE_USER=52; // not needed?
|
||||
const MARK_SENT_INVOICE=53; // not needed?
|
||||
const PAID_INVOICE=54; //
|
||||
const EMAIL_INVOICE_FAILED=57;
|
||||
const REVERSED_INVOICE=58;
|
||||
const CANCELLED_INVOICE=59;
|
||||
|
||||
const REVERSED_INVOICE=58; //
|
||||
const CANCELLED_INVOICE=59; //
|
||||
const VIEW_CREDIT=60; //
|
||||
|
||||
protected $casts = [
|
||||
'is_system' => 'boolean',
|
||||
'updated_at' => 'timestamp',
|
||||
@ -144,4 +151,16 @@ class Activity extends StaticModel
|
||||
{
|
||||
return $this->belongsTo(Company::class);
|
||||
}
|
||||
|
||||
|
||||
public function resolveRouteBinding($value)
|
||||
{
|
||||
if (is_numeric($value)) {
|
||||
throw new ModelNotFoundException("Record with value {$value} not found");
|
||||
}
|
||||
|
||||
return $this
|
||||
//->withTrashed()
|
||||
->where('id', $this->decodePrimaryKey($value))->firstOrFail();
|
||||
}
|
||||
}
|
||||
|
@ -194,7 +194,8 @@ class AuthorizeCreditCard
|
||||
}
|
||||
|
||||
private function processFailedResponse($data, $request)
|
||||
{ dd($data);
|
||||
{
|
||||
//dd($data);
|
||||
info(print_r($data,1));
|
||||
}
|
||||
|
||||
|
@ -12,12 +12,14 @@
|
||||
|
||||
namespace App\PaymentDrivers;
|
||||
|
||||
use App\Events\Invoice\InvoiceWasPaid;
|
||||
use App\Models\Client;
|
||||
use App\Models\ClientGatewayToken;
|
||||
use App\Models\CompanyGateway;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\PaymentDrivers\AbstractPaymentDriver;
|
||||
use App\Utils\Ninja;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use App\Utils\Traits\SystemLogTrait;
|
||||
|
||||
@ -119,6 +121,10 @@ class BaseDriver extends AbstractPaymentDriver
|
||||
|
||||
$payment->service()->applyNumber()->save();
|
||||
|
||||
$invoices->each(function ($invoice) use($payment){
|
||||
event(new InvoiceWasPaid($invoice, $payment->company, Ninja::eventVars()));
|
||||
});
|
||||
|
||||
return $payment;
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,7 @@ use App\Events\Credit\CreditWasEmailedAndFailed;
|
||||
use App\Events\Credit\CreditWasMarkedSent;
|
||||
use App\Events\Credit\CreditWasRestored;
|
||||
use App\Events\Credit\CreditWasUpdated;
|
||||
use App\Events\Credit\CreditWasViewed;
|
||||
use App\Events\Design\DesignWasArchived;
|
||||
use App\Events\Invoice\InvoiceWasArchived;
|
||||
use App\Events\Invoice\InvoiceWasCancelled;
|
||||
@ -76,17 +77,21 @@ use App\Listeners\Activity\RestoreClientActivity;
|
||||
use App\Listeners\Activity\UpdatedCreditActivity;
|
||||
use App\Listeners\Contact\UpdateContactLastLogin;
|
||||
use App\Listeners\Credit\CreditRestoredActivity;
|
||||
use App\Listeners\Credit\CreditViewedActivity;
|
||||
use App\Listeners\Document\DeleteCompanyDocuments;
|
||||
use App\Listeners\Invoice\CreateInvoiceActivity;
|
||||
use App\Listeners\Invoice\CreateInvoiceHtmlBackup;
|
||||
use App\Listeners\Invoice\CreateInvoiceInvitation;
|
||||
use App\Listeners\Invoice\CreateInvoicePdf;
|
||||
use App\Listeners\Invoice\InvoiceArchivedActivity;
|
||||
use App\Listeners\Invoice\InvoiceCancelledActivity;
|
||||
use App\Listeners\Invoice\InvoiceDeletedActivity;
|
||||
use App\Listeners\Invoice\InvoiceEmailActivity;
|
||||
use App\Listeners\Invoice\InvoiceEmailFailedActivity;
|
||||
use App\Listeners\Invoice\InvoiceEmailedNotification;
|
||||
use App\Listeners\Invoice\InvoicePaidActivity;
|
||||
use App\Listeners\Invoice\InvoiceRestoredActivity;
|
||||
use App\Listeners\Invoice\InvoiceReversedActivity;
|
||||
use App\Listeners\Invoice\InvoiceViewedActivity;
|
||||
use App\Listeners\Invoice\UpdateInvoiceActivity;
|
||||
use App\Listeners\Invoice\UpdateInvoiceInvitations;
|
||||
@ -194,6 +199,9 @@ class EventServiceProvider extends ServiceProvider
|
||||
CreditWasRestored::class => [
|
||||
CreditRestoredActivity::class,
|
||||
],
|
||||
CreditWasViewed::class => [
|
||||
CreditViewedActivity::class
|
||||
],
|
||||
//Designs
|
||||
DesignWasArchived::class => [
|
||||
],
|
||||
@ -216,7 +224,7 @@ class EventServiceProvider extends ServiceProvider
|
||||
// CreateInvoicePdf::class,
|
||||
],
|
||||
InvoiceWasPaid::class => [
|
||||
// CreateInvoiceHtmlBackup::class,
|
||||
InvoicePaidActivity::class,
|
||||
],
|
||||
InvoiceWasViewed::class => [
|
||||
InvoiceViewedActivity::class,
|
||||
@ -238,8 +246,10 @@ class EventServiceProvider extends ServiceProvider
|
||||
InvoiceRestoredActivity::class,
|
||||
],
|
||||
InvoiceWasReversed::class => [
|
||||
InvoiceReversedActivity::class,
|
||||
],
|
||||
InvoiceWasCancelled::class => [
|
||||
InvoiceCancelledActivity::class,
|
||||
],
|
||||
InvitationWasViewed::class => [
|
||||
InvitationViewedListener::class
|
||||
|
@ -66,8 +66,10 @@ class ActivityRepository extends BaseRepository
|
||||
{
|
||||
$backup = new Backup();
|
||||
|
||||
if (get_class($entity) == Invoice::class || get_class($entity) == Quote::class || get_class($entity) == Credit::class)
|
||||
$backup->html_backup = $this->generateEntityHtml($entity->getEntityDesigner(), $entity);
|
||||
if (get_class($entity) == Invoice::class || get_class($entity) == Quote::class || get_class($entity) == Credit::class){
|
||||
$contact = $entity->client->primary_contact()->first();
|
||||
$backup->html_backup = $this->generateEntityHtml($entity->getEntityDesigner(), $entity, $contact);
|
||||
}
|
||||
|
||||
$backup->activity_id = $activity->id;
|
||||
$backup->json_backup = '';
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
namespace App\Services\Invoice;
|
||||
|
||||
use App\Events\Invoice\InvoiceWasPaid;
|
||||
use App\Events\Payment\PaymentWasCreated;
|
||||
use App\Factory\PaymentFactory;
|
||||
use App\Models\Invoice;
|
||||
@ -72,6 +73,7 @@ class MarkPaid extends AbstractService
|
||||
|
||||
/* Update Invoice balance */
|
||||
event(new PaymentWasCreated($payment, $payment->company, Ninja::eventVars()));
|
||||
event(new InvoiceWasPaid($this->invoice, $payment->company, Ninja::eventVars()));
|
||||
|
||||
$payment->ledger()
|
||||
->updatePaymentBalance($payment->amount*-1);
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
namespace App\Services\Invoice;
|
||||
|
||||
use App\Events\Invoice\InvoiceWasMarkedSent;
|
||||
use App\Events\Invoice\InvoiceWasUpdated;
|
||||
use App\Models\Client;
|
||||
use App\Models\Invoice;
|
||||
use App\Services\AbstractService;
|
||||
@ -41,8 +41,6 @@ class MarkSent extends AbstractService
|
||||
|
||||
$this->invoice->setReminder();
|
||||
|
||||
event(new InvoiceWasMarkedSent($this->invoice, $this->invoice->company, Ninja::eventVars()));
|
||||
|
||||
$this->invoice
|
||||
->service()
|
||||
->setStatus(Invoice::STATUS_SENT)
|
||||
@ -54,6 +52,8 @@ class MarkSent extends AbstractService
|
||||
|
||||
$this->invoice->ledger()->updateInvoiceBalance($this->invoice->balance);
|
||||
|
||||
event(new InvoiceWasUpdated($this->invoice, $this->invoice->company, Ninja::eventVars()));
|
||||
|
||||
return $this->invoice->fresh();
|
||||
}
|
||||
}
|
||||
|
@ -96,4 +96,11 @@ class PaymentService
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function save()
|
||||
{
|
||||
$this->payment->save();
|
||||
|
||||
return $this->payment->fresh();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ class Phantom
|
||||
$phantom_url = "https://phantomjscloud.com/api/browser/v2/{$key}/?request=%7Burl:%22{$url}%22,renderType:%22pdf%22%7D";
|
||||
$pdf = \App\Utils\CurlUtils::get($phantom_url);
|
||||
|
||||
Storage::makeDirectory($path, 0755);
|
||||
Storage::makeDirectory($path, 0775);
|
||||
|
||||
$instance = Storage::disk(config('filesystems.default'))->put($file_path, $pdf);
|
||||
|
||||
|
@ -36,6 +36,7 @@ trait MakesInvoiceHtml
|
||||
*/
|
||||
public function generateEntityHtml(Designer $designer, $entity, $contact = null) :string
|
||||
{
|
||||
|
||||
$entity->load('client');
|
||||
|
||||
$client = $entity->client;
|
||||
|
@ -46,6 +46,16 @@ return [
|
||||
'local' => [
|
||||
'driver' => 'local',
|
||||
'root' => storage_path('app'),
|
||||
'permissions' => [
|
||||
'file' => [
|
||||
'public' => 0664,
|
||||
'private' => 0600,
|
||||
],
|
||||
'dir' => [
|
||||
'public' => 0775,
|
||||
'private' => 0700,
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
'public' => [
|
||||
@ -53,6 +63,16 @@ return [
|
||||
'root' => storage_path('app/public'),
|
||||
'url' => env('APP_URL').'/storage',
|
||||
'visibility' => 'public',
|
||||
'permissions' => [
|
||||
'file' => [
|
||||
'public' => 0664,
|
||||
'private' => 0600,
|
||||
],
|
||||
'dir' => [
|
||||
'public' => 0775,
|
||||
'private' => 0700,
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
's3' => [
|
||||
|
@ -3,7 +3,6 @@
|
||||
use App\DataMapper\ClientSettings;
|
||||
use App\DataMapper\CompanySettings;
|
||||
use App\DataMapper\DefaultSettings;
|
||||
use App\Events\Invoice\InvoiceWasMarkedSent;
|
||||
use App\Events\Invoice\InvoiceWasUpdated;
|
||||
use App\Events\Payment\PaymentWasCreated;
|
||||
use App\Helpers\Invoice\InvoiceSum;
|
||||
@ -200,8 +199,6 @@ class RandomDataSeeder extends Seeder
|
||||
|
||||
$invoice->ledger()->updateInvoiceBalance($invoice->balance);
|
||||
|
||||
event(new InvoiceWasMarkedSent($invoice, $company, Ninja::eventVars()));
|
||||
|
||||
if (rand(0, 1)) {
|
||||
$payment = App\Models\Payment::create([
|
||||
'date' => now(),
|
||||
|
@ -26,7 +26,9 @@ Route::group(['middleware' => ['api_db', 'token_auth', 'locale'], 'prefix' => 'a
|
||||
Route::get('ping', 'PingController@index')->name('ping');
|
||||
Route::get('health_check', 'PingController@health')->name('health_check');
|
||||
|
||||
Route::resource('activities', 'ActivityController');// name = (clients. index / create / show / update / destroy / edit
|
||||
Route::get('activities', 'ActivityController@index');
|
||||
|
||||
Route::get('activities/download_entity/{activity}', 'ActivityController@downloadHistoricalEntity');
|
||||
|
||||
Route::resource('clients', 'ClientController');// name = (clients. index / create / show / update / destroy / edit
|
||||
|
||||
|
@ -145,4 +145,76 @@ class InvoiceTest extends TestCase
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
|
||||
public function testUniqueNumberValidation()
|
||||
{
|
||||
/* stub a invoice in the DB that we will use to test against later */
|
||||
$invoice = factory(\App\Models\Invoice::class)->create([
|
||||
'user_id' => $this->user->id,
|
||||
'client_id' => $this->client->id,
|
||||
'company_id' => $this->company->id,
|
||||
'number' => 'test',
|
||||
]);
|
||||
|
||||
/* Test fire new invoice */
|
||||
$data = [
|
||||
'client_id' => $this->client->hashed_id,
|
||||
'number' => 'dude'
|
||||
];
|
||||
|
||||
$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();
|
||||
|
||||
$this->assertEquals('dude', $arr['data']['number']);
|
||||
|
||||
/*test validation fires*/
|
||||
$data = [
|
||||
'client_id' => $this->client->hashed_id,
|
||||
'number' => 'test'
|
||||
];
|
||||
|
||||
try{
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->put('/api/v1/invoices/' . $arr['data']['id'], $data)
|
||||
->assertStatus(302);
|
||||
|
||||
} catch (ValidationException $e) {
|
||||
|
||||
$message = json_decode($e->validator->getMessageBag(), 1);
|
||||
info("inside update invoice validator");
|
||||
info($message);
|
||||
$this->assertNotNull($message);
|
||||
}
|
||||
|
||||
$data = [
|
||||
'client_id' => $this->client->hashed_id,
|
||||
'number' => 'style'
|
||||
];
|
||||
|
||||
/* test number passed validation*/
|
||||
$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 = [
|
||||
'client_id' => $this->client->hashed_id,
|
||||
'number' => 'style'
|
||||
];
|
||||
|
||||
/* Make sure we can UPDATE using the same number*/
|
||||
$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);
|
||||
}
|
||||
}
|
||||
|
@ -155,7 +155,16 @@ class RefundTest extends TestCase
|
||||
|
||||
$this->invoice = $this->invoice_calc->getInvoice();
|
||||
$this->invoice->save();
|
||||
|
||||
$this->invoice->setRelation('client', $this->client);
|
||||
$this->invoice->setRelation('company', $this->company);
|
||||
|
||||
$this->invoice->service()->createInvitations()->markSent()->save();
|
||||
|
||||
$this->assertNotNull($this->invoice->invitations);
|
||||
|
||||
$this->assertNotNull($this->invoice->invitations->first()->contact);
|
||||
|
||||
$data = [
|
||||
'amount' => 50,
|
||||
'client_id' => $client->hashed_id,
|
||||
|
@ -65,7 +65,8 @@ class DesignTest extends TestCase
|
||||
|
||||
$this->invoice->uses_inclusive_taxes = false;
|
||||
|
||||
$this->invoice->service()->createInvitations()->markSent()->save();
|
||||
$this->invoice->service()->createInvitations()->markSent()->applyNumber()->save();
|
||||
|
||||
$this->invoice->fresh();
|
||||
$this->invoice->load('invitations');
|
||||
|
||||
|
85
tests/Integration/DownloadHistoricalInvoiceTest.php
Normal file
85
tests/Integration/DownloadHistoricalInvoiceTest.php
Normal file
@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Integration;
|
||||
|
||||
use App\Events\Invoice\InvoiceWasUpdated;
|
||||
use App\Models\Activity;
|
||||
use App\Repositories\ActivityRepository;
|
||||
use App\Utils\Ninja;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Foundation\Testing\Concerns\InteractsWithDatabase;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Tests\MockAccountData;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @covers App\Http\Controllers\ActivityController
|
||||
*/
|
||||
class DownloadHistoricalInvoiceTest extends TestCase
|
||||
{
|
||||
use MockAccountData;
|
||||
use DatabaseTransactions;
|
||||
use MakesHash;
|
||||
|
||||
public function setUp() :void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->makeTestData();
|
||||
}
|
||||
|
||||
private function mockActivity()
|
||||
{
|
||||
$activity_repo = new ActivityRepository();
|
||||
|
||||
$obj = new \stdClass;
|
||||
$obj->invoice_id = $this->invoice->id;
|
||||
$obj->user_id = $this->invoice->user_id;
|
||||
$obj->company_id = $this->company->id;
|
||||
|
||||
$activity_repo->save($obj, $this->invoice, Ninja::eventVars());
|
||||
|
||||
}
|
||||
public function testActivityAccessible()
|
||||
{
|
||||
$this->mockActivity();
|
||||
|
||||
$this->assertNotNull($this->invoice->activities);
|
||||
}
|
||||
|
||||
public function testBackupExists()
|
||||
{
|
||||
$this->mockActivity();
|
||||
|
||||
$this->assertNotNull($this->invoice->activities->first()->backup->html_backup);
|
||||
}
|
||||
|
||||
public function testBackupDownload()
|
||||
{
|
||||
$this->mockActivity();
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token
|
||||
])->get('/api/v1/activities/download_entity/'.$this->encodePrimaryKey($this->invoice->activities->first()->id));
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
|
||||
public function testBackupCheckPriorToDownloadWorks()
|
||||
{
|
||||
$this->mockActivity();
|
||||
|
||||
$backup = $this->invoice->activities->first()->backup;
|
||||
$backup->forceDelete();
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token
|
||||
])->get('/api/v1/activities/download_entity/'.$this->encodePrimaryKey($this->invoice->activities->first()->id));
|
||||
|
||||
$response->assertStatus(404);
|
||||
}
|
||||
}
|
@ -25,6 +25,7 @@ use App\Factory\InvoiceItemFactory;
|
||||
use App\Factory\InvoiceToRecurringInvoiceFactory;
|
||||
use App\Helpers\Invoice\InvoiceSum;
|
||||
use App\Models\Client;
|
||||
use App\Models\ClientContact;
|
||||
use App\Models\CompanyGateway;
|
||||
use App\Models\CompanyToken;
|
||||
use App\Models\Credit;
|
||||
@ -153,7 +154,7 @@ trait MockAccountData
|
||||
]);
|
||||
|
||||
|
||||
factory(\App\Models\ClientContact::class, 1)->create([
|
||||
$contact = factory(\App\Models\ClientContact::class, 1)->create([
|
||||
'user_id' => $this->user->id,
|
||||
'client_id' => $this->client->id,
|
||||
'company_id' => $this->company->id,
|
||||
@ -161,13 +162,17 @@ trait MockAccountData
|
||||
'send_email' => true,
|
||||
]);
|
||||
|
||||
factory(\App\Models\ClientContact::class, 1)->create([
|
||||
$contact2 = factory(\App\Models\ClientContact::class, 1)->create([
|
||||
'user_id' => $this->user->id,
|
||||
'client_id' => $this->client->id,
|
||||
'company_id' => $this->company->id,
|
||||
'send_email' => true
|
||||
]);
|
||||
|
||||
|
||||
// $rels = collect($contact, $contact2);
|
||||
// $this->client->setRelation('contacts', $rels);
|
||||
// $this->client->save();
|
||||
|
||||
$gs = new GroupSetting;
|
||||
$gs->name = 'Test';
|
||||
$gs->company_id = $this->client->company_id;
|
||||
|
Loading…
x
Reference in New Issue
Block a user