Fixes for invoice update and invoice designs (#3302)

* BaseController cleanup

* Working on invoice designs

* Working on invoice designs

* working on invoice designs

* working on invoice designs

* invoice designs

* Working on Invoice Designs

* Fixes for user settings object

* Working on invoice designs

* Fixes for encoded user settings

* Working on contact localized invoice pdfs

* working on invoice designs

* Fix for invoice update 500 error
This commit is contained in:
David Bomba 2020-02-10 20:53:02 +11:00 committed by GitHub
parent e8f19f9b63
commit 9a19f7fd4c
23 changed files with 1438 additions and 1204 deletions

View File

@ -483,7 +483,7 @@ class CreateTestData extends Command
UpdateInvoicePayment::dispatchNow($payment, $payment->company);
}
//@todo this slow things down, but gives us PDFs of the invoices for inspection whilst debugging.
//event(new InvoiceWasCreated($invoice, $invoice->company));
event(new InvoiceWasCreated($invoice, $invoice->company));
}
private function createCredit($client)

View File

@ -217,7 +217,7 @@ class CompanySettings extends BaseSettings
public $embed_documents = false;
public $all_pages_header = true;
public $all_pages_footer = true;
public $invoice_variables = [];
public static $casts = [
'auto_email_invoice' => 'bool',
@ -369,6 +369,7 @@ class CompanySettings extends BaseSettings
'counter_padding' => 'integer',
'design' => 'string',
'website' => 'string',
'invoice_variables' => 'object',
];
/**
@ -413,6 +414,7 @@ class CompanySettings extends BaseSettings
$data->date_format_id = (string)config('ninja.i18n.date_format_id');
$data->country_id = (string)config('ninja.i18n.country_id');
$data->translations = (object) [];
$data->invoice_variables = (array) self::getInvoiceVariableDefaults();
// $data->email_subject_invoice = EmailTemplateDefaults::emailInvoiceSubject();
// $data->email_template_invoice = EmailTemplateDefaults:: emailInvoiceTemplate();
@ -453,4 +455,53 @@ class CompanySettings extends BaseSettings
return $settings;
}
private static function getInvoiceVariableDefaults()
{
$variables = [
'client_details' => [
'name',
'id_number',
'vat_number',
'address1',
'address2',
'city_state_postal',
'country',
'email',
],
'company_details' => [
'company_name',
'id_number',
'vat_number',
'website',
'email',
'phone',
],
'company_address' => [
'address1',
'address2',
'city_state_postal',
'country',
],
'invoice_details' => [
'invoice_number',
'po_number',
'date',
'due_date',
'balance_due',
'invoice_total',
],
'table_columns' => [
'product_key',
'notes',
'cost',
'quantity',
'discount',
'tax_name1',
'line_total'
],
];
return $variables;
}
}

View File

@ -34,7 +34,7 @@ class DefaultSettings extends BaseSettings
public static function userSettings() : \stdClass
{
return (object)[
class_basename(User::class) => self::userSettingsObject(),
// class_basename(User::class) => self::userSettingsObject(),
];
}
@ -44,7 +44,7 @@ class DefaultSettings extends BaseSettings
private static function userSettingsObject() : \stdClass
{
return (object)[
'per_page' => self::$per_page,
// 'per_page' => self::$per_page,
];
}
}

View File

@ -11,6 +11,7 @@
namespace App\Designs;
use App\Models\Company;
use App\Models\Invoice;
class Designer
@ -24,11 +25,34 @@ class Designer
protected $html;
public function __construct($design, array $input_variables)
private static $custom_fields = [
'invoice1',
'invoice2',
'invoice3',
'invoice4',
'surcharge1',
'surcharge2',
'surcharge3',
'surcharge4',
'client1',
'client2',
'client3',
'client4',
'contact1',
'contact2',
'contact3',
'contact4',
'company1',
'company2',
'company3',
'company4',
];
public function __construct($design, $input_variables)
{
$this->design = $design;
$this->input_variables = $input_variables;
$this->input_variables = (array)$input_variables;
}
/**
@ -39,7 +63,7 @@ class Designer
public function build(Invoice $invoice) :Designer
{
$this->exportVariables()
$this->exportVariables($invoice)
->setDesign($this->getSection('header'))
->setDesign($this->getSection('body'))
->setDesign($this->getTable($invoice))
@ -86,14 +110,15 @@ class Designer
return str_replace(array_keys($this->exported_variables), array_values($this->exported_variables), $this->design->{$section}());
}
private function exportVariables()
private function exportVariables($invoice)
{
$company = $invoice->company;
$this->exported_variables['$client_details'] = $this->processVariables($this->input_variables['client_details'], $this->clientDetails());
$this->exported_variables['$company_details'] = $this->processVariables($this->input_variables['company_details'], $this->companyDetails());
$this->exported_variables['$company_address'] = $this->processVariables($this->input_variables['company_address'], $this->companyAddress());
$this->exported_variables['$invoice_details_labels'] = $this->processLabels($this->input_variables['invoice_details'], $this->invoiceDetails());
$this->exported_variables['$invoice_details'] = $this->processVariables($this->input_variables['invoice_details'], $this->invoiceDetails());
$this->exported_variables['$client_details'] = $this->processVariables($this->processInputVariables($company, $this->input_variables['client_details']), $this->clientDetails($company));
$this->exported_variables['$company_details'] = $this->processVariables($this->processInputVariables($company, $this->input_variables['company_details']), $this->companyDetails($company));
$this->exported_variables['$company_address'] = $this->processVariables($this->processInputVariables($company, $this->input_variables['company_address']), $this->companyAddress($company));
$this->exported_variables['$invoice_details_labels'] = $this->processLabels($this->processInputVariables($company, $this->input_variables['invoice_details']), $this->invoiceDetails($company));
$this->exported_variables['$invoice_details'] = $this->processVariables($this->processInputVariables($company, $this->input_variables['invoice_details']), $this->invoiceDetails($company));
return $this;
}
@ -153,10 +178,10 @@ class Designer
// $footer = $this->design->footer();
// }
private function clientDetails()
private function clientDetails(Company $company)
{
return [
$data = [
'name' => '<p>$client.name</p>',
'id_number' => '<p>$client.id_number</p>',
'vat_number' => '<p>$client.vat_number</p>',
@ -166,51 +191,59 @@ class Designer
'postal_city_state' => '<p>$client.postal_city_state</p>',
'country' => '<p>$client.country</p>',
'email' => '<p>$client.email</p>',
'custom_value1' => '<p>$client.custom_value1</p>',
'custom_value2' => '<p>$client.custom_value2</p>',
'custom_value3' => '<p>$client.custom_value3</p>',
'custom_value4' => '<p>$client.custom_value4</p>',
'client1' => '<p>$client1</p>',
'client2' => '<p>$client2</p>',
'client3' => '<p>$client3</p>',
'client4' => '<p>$client4</p>',
'contact1' => '<p>$contact1</p>',
'contact2' => '<p>$contact2</p>',
'contact3' => '<p>$contact3</p>',
'contact4' => '<p>$contact4</p>',
];
return $this->processCustomFields($company, $data);
}
private function companyDetails()
private function companyDetails(Company $company)
{
return [
$data = [
'company_name' => '<span>$company.company_name</span>',
'id_number' => '<span>$company.id_number</span>',
'vat_number' => '<span>$company.vat_number</span>',
'website' => '<span>$company.website</span>',
'email' => '<span>$company.email</span>',
'phone' => '<span>$company.phone</span>',
'custom_value1' => '<span>$company.custom_value1</span>',
'custom_value2' => '<span>$company.custom_value2</span>',
'custom_value3' => '<span>$company.custom_value3</span>',
'custom_value4' => '<span>$company.custom_value4</span>',
'company1' => '<span>$company1</span>',
'company2' => '<span>$company2</span>',
'company3' => '<span>$company3</span>',
'company4' => '<span>$company4</span>',
];
return $this->processCustomFields($company, $data);
}
private function companyAddress()
private function companyAddress(Company $company)
{
return [
$data = [
'address1' => '<span>$company.address1</span>',
'address2' => '<span>$company.address1</span>',
'city_state_postal' => '<span>$company.city_state_postal</span>',
'postal_city_state' => '<span>$company.postal_city_state</span>',
'country' => '<span>$company.country</span>',
'custom_value1' => '<span>$company.custom_value1</span>',
'custom_value2' => '<span>$company.custom_value2</span>',
'custom_value3' => '<span>$company.custom_value3</span>',
'custom_value4' => '<span>$company.custom_value4</span>',
'company1' => '<span>$company1</span>',
'company2' => '<span>$company2</span>',
'company3' => '<span>$company3</span>',
'company4' => '<span>$company4</span>',
];
return $this->processCustomFields($company, $data);
}
private function invoiceDetails()
private function invoiceDetails(Company $company)
{
return [
$data = [
'invoice_number' => '<span>$invoice_number</span>',
'po_number' => '<span>$po_number</span>',
'date' => '<span>$date</span>',
@ -218,11 +251,62 @@ class Designer
'balance_due' => '<span>$balance_due</span>',
'invoice_total' => '<span>$invoice_total</span>',
'partial_due' => '<span>$partial_due</span>',
'custom_value1' => '<span>$invoice.custom_value1</span>',
'custom_value2' => '<span>$invoice.custom_value2</span>',
'custom_value3' => '<span>$invoice.custom_value3</span>',
'custom_value4' => '<span>$invoice.custom_value4</span>',
'invoice1' => '<span>$invoice1</span>',
'invoice2' => '<span>$invoice2</span>',
'invoice3' => '<span>$invoice3</span>',
'invoice4' => '<span>$invoice4</span>',
'surcharge1' =>'<span>$surcharge1</span>',
'surcharge2' =>'<span>$surcharge2</span>',
'surcharge3' =>'<span>$surcharge3</span>',
'surcharge4' =>'<span>$surcharge4</span>',
];
return $this->processCustomFields($company, $data);
}
private function processCustomFields(Company $company, $data)
{
$custom_fields = $company->custom_fields;
foreach(self::$custom_fields as $cf)
{
if(!property_exists($custom_fields, $cf) || (strlen($custom_fields->{$cf}) == 0))
unset($data[$cf]);
}
return $data;
}
private function processInputVariables($company, $variables)
{
$custom_fields = $company->custom_fields;
$matches = array_intersect(self::$custom_fields, $variables);
foreach($matches as $match)
{
if(!property_exists($custom_fields, $match) || (strlen($custom_fields->{$match}) == 0))
{
foreach($variables as $key => $value)
{
if($value == $match)
{
unset($variables[$key]);
}
}
}
}
return $variables;
}
}

File diff suppressed because one or more lines are too long

View File

@ -31,7 +31,8 @@ class CompanyFactory
$company->company_key = $this->createHash();
$company->settings = CompanySettings::defaults();
$company->db = config('database.default');
$company->custom_fields = (object) ['custom1' => '1', 'custom2' => '2', 'custom3'=>'3'];
//$company->custom_fields = (object) ['invoice1' => '1', 'invoice2' => '2', 'client1'=>'3'];
$company->custom_fields = (object) [];
$company->subdomain = '';
return $company;

View File

@ -56,32 +56,35 @@ class BaseController extends Controller
public function __construct()
{
$this->manager = new Manager();
$this->forced_includes = [];
$this->forced_index = 'data';
}
private function buildManager()
{
$include = '';
if(request()->has('first_load') && request()->input('first_load') == 'true') {
$include = $this->getRequestIncludes([]);
$include = array_merge($this->forced_includes, $include);
$include = implode("," , array_merge($this->forced_includes, $this->getRequestIncludes([])));
$include = implode(",", $include);
}
else if (request()->input('include') !== null) {
$request_include = explode(",", request()->input('include'));
$include = array_merge($this->forced_includes, $request_include);
$include = array_merge($this->forced_includes, explode(",", request()->input('include')));
$include = implode(",", $include);
} elseif (count($this->forced_includes) >= 1) {
$include = implode(",", $this->forced_includes);
}
$this->manager->parseIncludes($include);
@ -89,10 +92,15 @@ class BaseController extends Controller
$this->serializer = request()->input('serializer') ?: EntityTransformer::API_SERIALIZER_ARRAY;
if ($this->serializer === EntityTransformer::API_SERIALIZER_JSON) {
$this->manager->setSerializer(new JsonApiSerializer());
} else {
$this->manager->setSerializer(new ArraySerializer());
}
}
/**
@ -101,27 +109,36 @@ class BaseController extends Controller
*/
public function notFound()
{
return response()->json(['message' => '404 | Nothing to see here!'], 404)
->header('X-API-VERSION', config('ninja.api_version'))
->header('X-APP-VERSION', config('ninja.app_version'));
}
public function notFoundClient()
{
return abort(404);
}
protected function errorResponse($response, $httpErrorCode = 400)
{
$error['error'] = $response;
$error = json_encode($error, JSON_PRETTY_PRINT);
$headers = self::getApiHeaders();
return response()->make($error, $httpErrorCode, $headers);
}
protected function listResponse($query)
{
$this->buildManager();
$transformer = new $this->entity_transformer(Input::get('serializer'));
@ -145,32 +162,40 @@ class BaseController extends Controller
$data = $this->createCollection($query, $transformer, $this->entity_type);
return $this->response($data);
}
protected function createCollection($query, $transformer, $entity_type)
{
$this->buildManager();
if ($this->serializer && $this->serializer != EntityTransformer::API_SERIALIZER_JSON) {
if ($this->serializer && $this->serializer != EntityTransformer::API_SERIALIZER_JSON)
$entity_type = null;
}
if (is_a($query, "Illuminate\Database\Eloquent\Builder")) {
$limit = Input::get('per_page', 20);
$paginator = $query->paginate($limit);
$query = $paginator->getCollection();
$resource = new Collection($query, $transformer, $entity_type);
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
} else {
$resource = new Collection($query, $transformer, $entity_type);
}
return $this->manager->createData($resource)->toArray();
}
protected function response($response)
{
$index = request()->input('index') ?: $this->forced_index;
if ($index == 'none') {
@ -194,55 +219,50 @@ class BaseController extends Controller
ksort($response);
$response = json_encode($response, JSON_PRETTY_PRINT);
$headers = self::getApiHeaders();
return response()->make($response, 200, $headers);
}
protected function itemResponse($item)
{
$this->buildManager();
$transformer = new $this->entity_transformer(Input::get('serializer'));
$data = $this->createItem($item, $transformer, $this->entity_type);
if (request()->include_static) {
if (request()->include_static)
$data['static'] = Statics::company(auth()->user()->getCompany()->getLocale());
}
return $this->response($data);
}
protected function createItem($data, $transformer, $entity_type)
{
if ($this->serializer && $this->serializer != EntityTransformer::API_SERIALIZER_JSON) {
$entity_type = null;
}
if ($this->serializer && $this->serializer != EntityTransformer::API_SERIALIZER_JSON)
$entity_type = null;
$resource = new Item($data, $transformer, $entity_type);
return $this->manager->createData($resource)->toArray();
}
public static function getApiHeaders($count = 0)
{
return [
'Content-Type' => 'application/json',
//'Access-Control-Allow-Origin' => '*',
//'Access-Control-Allow-Methods' => 'GET',
//'Access-Control-Allow-Headers' => 'Origin, Content-Type, Accept, Authorization, X-Requested-With',
//'Access-Control-Allow-Credentials' => 'true',
//'X-Total-Count' => $count,
'X-Api-Version' => config('ninja.api_version'),
'X-App-Version' => config('ninja.app_version'),
//'X-Rate-Limit-Limit' - The number of allowed requests in the current period
//'X-Rate-Limit-Remaining' - The number of remaining requests in the current period
//'X-Rate-Limit-Reset' - The number of seconds left in the current period,
];
}
@ -279,7 +299,9 @@ class BaseController extends Controller
'company.groups',
];
/**
* Thresholds for displaying large account on first load
*/
if (request()->has('first_load') && request()->input('first_load') == 'true')
{
@ -315,4 +337,5 @@ class BaseController extends Controller
return $data;
}
}

View File

@ -24,25 +24,23 @@ use App\Http\Requests\Invoice\EditInvoiceRequest;
use App\Http\Requests\Invoice\ShowInvoiceRequest;
use App\Http\Requests\Invoice\StoreInvoiceRequest;
use App\Http\Requests\Invoice\UpdateInvoiceRequest;
use App\Jobs\Entity\ActionEntity;
use App\Jobs\Invoice\EmailInvoice;
use App\Jobs\Invoice\MarkInvoicePaid;
use App\Jobs\Invoice\StoreInvoice;
use App\Models\Invoice;
use App\Repositories\BaseRepository;
use App\Repositories\InvoiceRepository;
use App\Transformers\InvoiceTransformer;
use App\Utils\Traits\MakesHash;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
/**
* Class InvoiceController
* @package App\Http\Controllers\InvoiceController
*/
class InvoiceController extends BaseController
{
class InvoiceController extends BaseController {
use MakesHash;
protected $entity_type = Invoice::class ;
@ -59,8 +57,7 @@ class InvoiceController extends BaseController
*
* @param \App\Repositories\InvoiceRepository $invoice_repo The invoice repo
*/
public function __construct(InvoiceRepository $invoice_repo)
{
public function __construct(InvoiceRepository $invoice_repo) {
parent::__construct();
$this->invoice_repo = $invoice_repo;
@ -107,8 +104,7 @@ class InvoiceController extends BaseController
* )
*
*/
public function index(InvoiceFilters $filters)
{
public function index(InvoiceFilters $filters) {
$invoices = Invoice::filter($filters);
return $this->listResponse($invoices);
@ -154,14 +150,12 @@ class InvoiceController extends BaseController
* )
*
*/
public function create(CreateInvoiceRequest $request)
{
public function create(CreateInvoiceRequest $request) {
$invoice = InvoiceFactory::create(auth()->user()->company()->id, auth()->user()->id);
return $this->itemResponse($invoice);
}
/**
* Store a newly created resource in storage.
*
@ -202,8 +196,7 @@ class InvoiceController extends BaseController
* )
*
*/
public function store(StoreInvoiceRequest $request)
{
public function store(StoreInvoiceRequest $request) {
$invoice = $this->invoice_repo->save($request->all(), InvoiceFactory::create(auth()->user()->company()->id, auth()->user()->id));
$invoice = StoreInvoice::dispatchNow($invoice, $request->all(), $invoice->company);//todo potentially this may return mixed ie PDF/$invoice... need to revisit when we implement UI
@ -265,8 +258,7 @@ class InvoiceController extends BaseController
* )
*
*/
public function show(ShowInvoiceRequest $request, Invoice $invoice)
{
public function show(ShowInvoiceRequest $request, Invoice $invoice) {
return $this->itemResponse($invoice);
}
@ -321,8 +313,7 @@ class InvoiceController extends BaseController
* )
*
*/
public function edit(EditInvoiceRequest $request, Invoice $invoice)
{
public function edit(EditInvoiceRequest $request, Invoice $invoice) {
return $this->itemResponse($invoice);
}
@ -378,10 +369,10 @@ class InvoiceController extends BaseController
* )
*
*/
public function update(UpdateInvoiceRequest $request, Invoice $invoice)
{
if($request->entityIsDeleted($invoice))
public function update(UpdateInvoiceRequest $request, Invoice $invoice) {
if ($request->entityIsDeleted($invoice)) {
return $request->disallowUpdate();
}
$invoice = $this->invoice_repo->save($request->all(), $invoice);
@ -440,8 +431,7 @@ class InvoiceController extends BaseController
* )
*
*/
public function destroy(DestroyInvoiceRequest $request, Invoice $invoice)
{
public function destroy(DestroyInvoiceRequest $request, Invoice $invoice) {
$invoice->delete();
return response()->json([], 200);
@ -499,8 +489,7 @@ class InvoiceController extends BaseController
* )
*
*/
public function bulk()
{
public function bulk() {
$action = request()->input('action');
$ids = request()->input('ids');
@ -590,13 +579,11 @@ class InvoiceController extends BaseController
* )
*
*/
public function action(ActionInvoiceRequest $request, Invoice $invoice, $action)
{
public function action(ActionInvoiceRequest $request, Invoice $invoice, $action) {
return $this->performAction($invoice, $action);
}
private function performAction(Invoice $invoice, $action, $bulk = false)
{
private function performAction(Invoice $invoice, $action, $bulk = false) {
/*If we are using bulk actions, we don't want to return anything */
switch ($action) {
case 'clone_to_invoice':
@ -660,4 +647,13 @@ class InvoiceController extends BaseController
break;
}
}
public function downloadPdf($invitation_key) {
$invitation = InvoiceInvitation::whereKey($invitation_key)->company()->first();
$contact = $invitation->contact;
$invoice = $invitation->invoice;
return response()->json($invitation_key);
}
}

View File

@ -11,6 +11,9 @@
namespace App\Http\Controllers;
use Codedge\Updater\UpdaterManager;
use Illuminate\Foundation\Bus\DispatchesJobs;
class SelfUpdateController extends BaseController
{
use DispatchesJobs;
@ -20,8 +23,10 @@ class SelfUpdateController extends BaseController
}
public function update()
public function update(UpdaterManager $updater)
{
$updater->update();
}
}

View File

@ -103,8 +103,8 @@ class TemplateController extends BaseController
$entity_obj = $class::whereId(request()->input('entity_id'))->company()->first();
}
$subject = request()->input('subject');
$body = request()->input('body');
$subject = request()->input('subject') ?: '';
$body = request()->input('body') ?: '';
$converter = new CommonMarkConverter([
'html_input' => 'strip',

View File

@ -14,11 +14,10 @@ namespace App\Jobs\Invoice;
use App\Designs\Designer;
use App\Designs\Modern;
use App\Libraries\MultiDB;
use App\Models\ClientContact;
use App\Models\Company;
use App\Models\Invoice;
use App\Models\Payment;
use App\Models\PaymentTerm;
use App\Repositories\InvoiceRepository;
use App\Utils\Traits\MakesInvoiceHtml;
use App\Utils\Traits\NumberFormatter;
use Illuminate\Bus\Queueable;
@ -26,121 +25,58 @@ use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Storage;
use Spatie\Browsershot\Browsershot;
use Symfony\Component\Debug\Exception\FatalThrowableError;
class CreateInvoicePdf implements ShouldQueue
{
class CreateInvoicePdf implements ShouldQueue {
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, NumberFormatter, MakesInvoiceHtml;
public $invoice;
public $company;
public $contact;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct(Invoice $invoice, Company $company)
{
public function __construct(Invoice $invoice, Company $company, ClientContact $contact) {
$this->invoice = $invoice;
$this->company = $company;
$this->contact = $contact;
}
public function handle()
{
public function handle() {
MultiDB::setDB($this->company->db);
$input_variables = [
'client_details' => [
'name',
'id_number',
'vat_number',
'address1',
'address2',
'city_state_postal',
'postal_city_state',
'country',
'email',
'custom_value1',
'custom_value2',
'custom_value3',
'custom_value4',
],
'company_details' => [
'company_name',
'id_number',
'vat_number',
'website',
'email',
'phone',
'custom_value1',
'custom_value2',
'custom_value3',
'custom_value4',
],
'company_address' => [
'address1',
'address2',
'city_state_postal',
'postal_city_state',
'country',
'custom_value1',
'custom_value2',
'custom_value3',
'custom_value4',
],
'invoice_details' => [
'invoice_number',
'po_number',
'date',
'due_date',
'balance_due',
'invoice_total',
'partial_due',
'custom_value1',
'custom_value2',
'custom_value3',
'custom_value4',
],
'table_columns' => [
'product_key',
'notes',
'cost',
'quantity',
'discount',
'tax_name1',
'line_total'
],
];
App::setLocale($this->contact->preferredLocale());
$this->invoice->load('client');
$path = 'public/'.$this->invoice->client->client_hash.'/invoices/';
$file_path = $path.$this->invoice->number.'.pdf';
$modern = new Modern();
$designer = new Designer($modern, $input_variables);
$designer = new Designer($modern, $this->invoice->client->getSetting('invoice_variables'));
//get invoice design
$html = $this->generateInvoiceHtml($designer->build($this->invoice)->getHtml(), $this->invoice);
$html = $this->generateInvoiceHtml($designer->build($this->invoice)->getHtml(), $this->invoice, $this->contact);
//todo - move this to the client creation stage so we don't keep hitting this unnecessarily
Storage::makeDirectory($path, 0755);
\Log::error($html);
//\Log::error($html);
//create pdf
$pdf = $this->makePdf(null, null, $html);
$path = Storage::put($file_path, $pdf);
return $path;
}
/**
@ -152,15 +88,14 @@ class CreateInvoicePdf implements ShouldQueue
*
* @return string The PDF string
*/
private function makePdf($header, $footer, $html)
{
private function makePdf($header, $footer, $html) {
return Browsershot::html($html)
//->showBrowserHeaderAndFooter()
//->headerHtml($header)
//->footerHtml($footer)
->deviceScaleFactor(1)
->showBackground()
->waitUntilNetworkIdle(false)->pdf();
->waitUntilNetworkIdle(true) ->pdf();
//->margins(10,10,10,10)
//->savePdf('test.pdf');
}

View File

@ -35,6 +35,6 @@ class CreateInvoicePdf implements ShouldQueue
*/
public function handle($event)
{
PdfCreator::dispatch($event->invoice, $event->company);
PdfCreator::dispatch($event->invoice, $event->company, $event->invoice->client->primary_contact()->first());
}
}

View File

@ -32,13 +32,14 @@ use App\Utils\Traits\GeneratesCounter;
use App\Utils\Traits\MakesDates;
use App\Utils\Traits\MakesHash;
use Hashids\Hashids;
use Illuminate\Contracts\Translation\HasLocalePreference;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\URL;
use Laracasts\Presenter\PresentableTrait;
class Client extends BaseModel
class Client extends BaseModel implements HasLocalePreference
{
use PresentableTrait;
use MakesHash;
@ -424,4 +425,18 @@ class Client extends BaseModel
return $payment_urls;
}
public function preferredLocale()
{
$languages = Cache::get('languages');
return $languages->filter(function ($item) {
return $item->id == $this->client->getSetting('language_id');
})->first()->locale;
//$lang = Language::find($this->client->getSetting('language_id'));
//return $lang->locale;
}
}

View File

@ -33,7 +33,6 @@ use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Laracasts\Presenter\PresentableTrait;
@ -349,7 +348,7 @@ class Invoice extends BaseModel
if (!Storage::exists($storage_path)) {
event(new InvoiceWasUpdated($this, $this->company));
CreateInvoicePdf::dispatch($this, $this->company);
CreateInvoicePdf::dispatch($this, $this->company, $this->client->primary_contact()->first());
}
return $public_path;
@ -360,7 +359,7 @@ class Invoice extends BaseModel
$storage_path = 'storage/' . $this->client->client_hash . '/invoices/'. $this->number . '.pdf';
if (!Storage::exists($storage_path)) {
CreateInvoicePdf::dispatchNow($this, $this->company);
CreateInvoicePdf::dispatchNow($this, $this->company, $this->client->primary_contact()->first());
}
return $storage_path;

View File

@ -14,64 +14,57 @@ namespace App\Models;
use App\Models\Invoice;
use App\Utils\Traits\Inviteable;
use App\Utils\Traits\MakesDates;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Carbon;
class InvoiceInvitation extends BaseModel
{
class InvoiceInvitation extends BaseModel {
use MakesDates;
use SoftDeletes;
use Inviteable;
protected $fillable = [
'id',
'client_contact_id',
//'id',
//'client_contact_id',
];
protected $with = [
// 'company',
];
public function entityType()
{
public function entityType() {
return Invoice::class ;
}
/**
* @return mixed
*/
public function invoice()
{
public function invoice() {
return $this->belongsTo(Invoice::class )->withTrashed();
}
/**
* @return mixed
*/
public function contact()
{
public function contact() {
return $this->belongsTo(ClientContact::class , 'client_contact_id', 'id')->withTrashed();
}
/**
* @return mixed
*/
public function user()
{
public function user() {
return $this->belongsTo(User::class )->withTrashed();
}
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function company()
{
public function company() {
return $this->belongsTo(Company::class );
}
public function signatureDiv()
{
public function signatureDiv() {
if (!$this->signature_base64) {
return false;
}
@ -79,13 +72,11 @@ class InvoiceInvitation extends BaseModel
return sprintf('<img src="data:image/svg+xml;base64,%s"></img><p/>%s: %s', $this->signature_base64, ctrans('texts.signed'), $this->createClientDate($this->signature_date, $this->contact->client->timezone()->name));
}
public function getName()
{
public function getName() {
return $this->key;
}
public function markViewed()
{
public function markViewed() {
$this->viewed_date = Carbon::now();
$this->save();
}

View File

@ -11,25 +11,21 @@
namespace App\Repositories;
use App\Events\Invoice\InvoiceWasCreated;
use App\Events\Invoice\InvoiceWasUpdated;
use App\Factory\InvoiceInvitationFactory;
use App\Helpers\Invoice\InvoiceSum;
use App\Jobs\Company\UpdateCompanyLedgerWithInvoice;
use App\Jobs\Product\UpdateOrCreateProduct;
use App\Listeners\Invoice\CreateInvoiceInvitation;
use App\Models\ClientContact;
use App\Models\Invoice;
use App\Models\InvoiceInvitation;
use App\Utils\Traits\MakesHash;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
/**
* InvoiceRepository
*/
class InvoiceRepository extends BaseRepository
{
class InvoiceRepository extends BaseRepository {
use MakesHash;
/**
@ -37,8 +33,7 @@ class InvoiceRepository extends BaseRepository
*
* @return string The class name.
*/
public function getClassName()
{
public function getClassName() {
return Invoice::class ;
}
@ -50,8 +45,7 @@ class InvoiceRepository extends BaseRepository
*
* @return Invoice|InvoiceSum|\App\Models\Invoice|null Returns the invoice object
*/
public function save($data, Invoice $invoice) : ?Invoice
{
public function save($data, Invoice $invoice):?Invoice {
/* Always carry forward the initial invoice amount this is important for tracking client balance changes later......*/
$starting_amount = $invoice->amount;
@ -129,8 +123,7 @@ class InvoiceRepository extends BaseRepository
*
* @return Invoice|\App\Models\Invoice|null Return the invoice object
*/
public function markSent(Invoice $invoice) : ?Invoice
{
public function markSent(Invoice $invoice):?Invoice {
return $invoice->service()->markSent()->save();
}
}

View File

@ -11,6 +11,7 @@
namespace App\Utils\Traits;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Blade;
use Symfony\Component\Debug\Exception\FatalThrowableError;
@ -29,11 +30,20 @@ trait MakesInvoiceHtml
*
* @return string The invoice string in HTML format
*/
public function generateInvoiceHtml($design, $invoice) :string
public function generateInvoiceHtml($design, $invoice, $contact = null) :string
{
$variables = array_merge($invoice->makeLabels(), $invoice->makeValues());
//$variables = array_merge($invoice->makeLabels(), $invoice->makeValues());
//$design = str_replace(array_keys($variables), array_values($variables), $design);
if(!$contact)
$contact = $invoice->client->primary_contact()->first();
$design = str_replace(array_keys($variables), array_values($variables), $design);
App::setLocale($contact->preferredLocale());
$labels = $invoice->makeLabels();
$values = $invoice->makeValues($contact);
$design = str_replace(array_keys($labels), array_values($labels), $design);
$design = str_replace(array_keys($values), array_values($values), $design);
$data['invoice'] = $invoice;

View File

@ -119,10 +119,10 @@ trait MakesInvoiceValues
'service',
'product_key',
'unit_cost',
'custom_value1',
'custom_value2',
'custom_value3',
'custom_value4',
// 'custom_value1',
// 'custom_value2',
// 'custom_value3',
// 'custom_value4',
'delivery_note',
'date',
'method',
@ -130,6 +130,49 @@ trait MakesInvoiceValues
'reference',
'amount',
'amount_paid',
'invoice1',
'invoice2',
'invoice3',
'invoice4',
'surcharge1',
'surcharge2',
'surcharge3',
'surcharge4',
'client1',
'client2',
'client3',
'client4',
'contact1',
'contact2',
'contact3',
'contact4',
'company1',
'company2',
'company3',
'company4',
];
private static $custom_label_fields = [
'invoice1',
'invoice2',
'invoice3',
'invoice4',
'surcharge1',
'surcharge2',
'surcharge3',
'surcharge4',
'client1',
'client2',
'client3',
'client4',
'contact1',
'contact2',
'contact3',
'contact4',
'company1',
'company2',
'company3',
'company4',
];
/**
@ -150,8 +193,49 @@ trait MakesInvoiceValues
$data['$'.$label . '_label'] = ctrans('texts.'.$label);
}
if($custom_fields && property_exists($custom_fields,'invoice_text1'))
$data['$invoice_text1'] = $custom_fields->invoice_text1;
if($custom_fields)
{
foreach($custom_fields as $key => $value)
{
if(strpos($value, '|') !== false)
{
$value = explode("|", $value);
$value = $value[0];
}
$data['$'.$key.'_label'] = $value;
}
}
/*
Don't forget pipe | strings for dropdowns needs to be filtered
*/
/*
invoice1
invoice2
invoice3
invoice4
surcharge1
surcharge2
surcharge3
surcharge4
client1
client2
client3
client4
contact1
contact2
contact3
contact4
*/
$arrKeysLength = array_map('strlen', array_keys($data));
array_multisort($arrKeysLength, SORT_DESC, $data);
return $data;
}
@ -179,18 +263,18 @@ trait MakesInvoiceValues
$data['$line_tax_labels'] = $this->lineTaxLabels();
$data['$line_tax_values'] = $this->lineTaxValues();
$data['$date'] = $this->date;
$data['$date'] = $this->date ?: '&nbsp;';
$data['$invoice.date'] = &$data['$date'];
$data['$due_date'] = $this->due_date;
$data['$due_date'] = $this->due_date ?: '&nbsp;';
$data['$invoice.due_date'] = &$data['$due_date'];
$data['$number'] = $this->number;
$data['$number'] = $this->number ?: '&nbsp;';
$data['$invoice.number'] = &$data['$number'];
$data['$invoice_number'] = &$data['$number'];
$data['$po_number'] = $this->po_number;
$data['$po_number'] = $this->po_number ?: '&nbsp;';
$data['$invoice.po_number'] = &$data['$po_number'];
$data['$line_taxes'] = $this->makeLineTaxes();
$data['$line_taxes'] = $this->makeLineTaxes() ?: '&nbsp;';
$data['$invoice.line_taxes'] = &$data['$line_taxes'];
$data['$total_taxes'] = $this->makeTotalTaxes();
$data['$total_taxes'] = $this->makeTotalTaxes() ?: '&nbsp;';
$data['$invoice.total_taxes'] = &$data['$total_taxes'];
// $data['$tax'] = ;
// $data['$item'] = ;
@ -199,31 +283,31 @@ trait MakesInvoiceValues
// $data['$quantity'] = ;
// $data['$line_total'] = ;
// $data['$paid_to_date'] = ;
$data['$discount'] = Number::formatMoney($this->calc()->getTotalDiscount(), $this->client);
$data['$discount'] = Number::formatMoney($this->calc()->getTotalDiscount(), $this->client) ?: '&nbsp;';
$data['$invoice.discount'] = &$data['$discount'];
$data['$subtotal'] = Number::formatMoney($this->calc()->getSubTotal(), $this->client);
$data['$subtotal'] = Number::formatMoney($this->calc()->getSubTotal(), $this->client) ?: '&nbsp;';
$data['$invoice.subtotal'] = &$data['$subtotal'];
$data['$balance_due'] = Number::formatMoney($this->balance, $this->client);
$data['$balance_due'] = Number::formatMoney($this->balance, $this->client) ?: '&nbsp;';
$data['$invoice.balance_due'] = &$data['$balance_due'];
$data['$partial_due'] = Number::formatMoney($this->partial, $this->client);
$data['$partial_due'] = Number::formatMoney($this->partial, $this->client) ?: '&nbsp;';
$data['$invoice.partial_due'] = &$data['$partial_due'];
$data['$total'] = Number::formatMoney($this->calc()->getTotal(), $this->client);
$data['$total'] = Number::formatMoney($this->calc()->getTotal(), $this->client) ?: '&nbsp;';
$data['$invoice.total'] = &$data['$total'];
$data['$amount'] = &$data['$total'];
$data['$invoice_total'] = &$data['$total'];
$data['$invoice.amount'] = &$data['$total'];
$data['$balance'] = Number::formatMoney($this->calc()->getBalance(), $this->client);
$data['$balance'] = Number::formatMoney($this->calc()->getBalance(), $this->client) ?: '&nbsp;';
$data['$invoice.balance'] = &$data['$balance'];
$data['$taxes'] = Number::formatMoney($this->calc()->getItemTotalTaxes(), $this->client);
$data['$taxes'] = Number::formatMoney($this->calc()->getItemTotalTaxes(), $this->client) ?: '&nbsp;';
$data['$invoice.taxes'] = &$data['$taxes'];
$data['$terms'] = $this->terms;
$data['$terms'] = $this->terms ?: '&nbsp;';
$data['$invoice.terms'] = &$data['$terms'];
$data['$invoice.custom_value1'] = $this->custom_value1;
$data['$invoice.custom_value2'] = $this->custom_value2;
$data['$invoice.custom_value3'] = $this->custom_value3;
$data['$invoice.custom_value4'] = $this->custom_value4;
$data['$invoice.public_notes'] = $this->public_notes;
$data['$invoice1'] = $this->custom_value1 ?: '&nbsp;';
$data['$invoice2'] = $this->custom_value2 ?: '&nbsp;';
$data['$invoice3'] = $this->custom_value3 ?: '&nbsp;';
$data['$invoice4'] = $this->custom_value4 ?: '&nbsp;';
$data['$invoice.public_notes'] = $this->public_notes ?: '&nbsp;';
// $data['$your_invoice'] = ;
// $data['$quote'] = ;
// $data['$your_quote'] = ;
@ -238,74 +322,74 @@ trait MakesInvoiceValues
// $data['$invoice_to'] = ;
// $data['$quote_to'] = ;
// $data['$details'] = ;
$data['$invoice_no'] = $this->number;
$data['$invoice_no'] = $this->number ?: '&nbsp;';
$data['$invoice.invoice_no'] = &$data['$invoice_no'];
// $data['$quote_no'] = ;
// $data['$valid_until'] = ;
$data['$client_name'] = $this->present()->clientName();
$data['$client1'] = $this->client->custom_value1 ?: '&nbsp;';
$data['$client2'] = $this->client->custom_value2 ?: '&nbsp;';
$data['$client3'] = $this->client->custom_value3 ?: '&nbsp;';
$data['$client4'] = $this->client->custom_value4 ?: '&nbsp;';
$data['$client_name'] = $this->present()->clientName() ?: '&nbsp;';
$data['$client.name'] = &$data['$client_name'];
$data['$client_address'] = $this->present()->address();
$data['$client.address'] = &$data['$client_address'];
$data['$address1'] = $this->client->address1;
$data['$client.address1'] = &$data['$address1'];
$data['$address2'] = $this->client->address2;
$data['$address1'] = $this->client->address1 ?: '&nbsp;';
$data['$address2'] = $this->client->address2 ?: '&nbsp;';
$data['$client.address2'] = &$data['$address2'];
$data['$id_number'] = $this->client->id_number;
$data['$client.address1'] = &$data['$address1'];
$data['$client.address'] = &$data['$client_address'];
$data['$client_address'] = $this->present()->address() ?: '&nbsp;';
$data['$id_number'] = $this->client->id_number ?: '&nbsp;';
$data['$client.id_number'] = &$data['$id_number'];
$data['$vat_number'] = $this->client->vat_number;
$data['$vat_number'] = $this->client->vat_number ?: '&nbsp;';
$data['$client.vat_number'] = &$data['$vat_number'];
$data['$website'] = $this->client->present()->website();
$data['$website'] = $this->client->present()->website() ?: '&nbsp;';
$data['$client.website'] = &$data['$website'];
$data['$phone'] = $this->client->present()->phone();
$data['$phone'] = $this->client->present()->phone() ?: '&nbsp;';
$data['$client.phone'] = &$data['$phone'];
$data['$city_state_postal'] = $this->present()->cityStateZip($this->client->city, $this->client->state, $this->client->postal_code, false);
$data['$city_state_postal'] = $this->present()->cityStateZip($this->client->city, $this->client->state, $this->client->postal_code, false) ?: '&nbsp;';
$data['$client.city_state_postal'] = &$data['$city_state_postal'];
$data['$postal_city_state'] = $this->present()->cityStateZip($this->client->city, $this->client->state, $this->client->postal_code, true);
$data['$postal_city_state'] = $this->present()->cityStateZip($this->client->city, $this->client->state, $this->client->postal_code, true) ?: '&nbsp;';
$data['$client.postal_city_state'] = &$data['$postal_city_state'];
$data['$country'] = isset($this->client->country->name) ?: 'No Country Set';
$data['$country'] = isset($this->client->country->name) ? $this->client->country->name : 'No Country Set';
$data['$client.country'] = &$data['$country'];
$data['$email'] = isset($this->client->primary_contact()->first()->email) ?: 'no contact email on record';
$data['$email'] = isset($this->client->primary_contact()->first()->email) ? $this->client->primary_contact()->first()->email : 'no contact email on record';
$data['$client.email'] = &$data['$email'];
$data['$client.custom_value1'] = $this->client->custom_value1;
$data['$client.custom_value2'] = $this->client->custom_value2;
$data['$client.custom_value3'] = $this->client->custom_value3;
$data['$client.custom_value4'] = $this->client->custom_value4;
if(!$contact)
$contact = $this->client->primary_contact()->first();
$data['$contact_name'] = isset($contact) ? $contact->present()->name() : 'no contact name on record';
$data['$contact.name'] = &$data['$contact_name'];
$data['$contact.custom_value1'] = isset($contact) ? $contact->custom_value1 : '';
$data['$contact.custom_value2'] = isset($contact) ? $contact->custom_value2 : '';
$data['$contact.custom_value3'] = isset($contact) ? $contact->custom_value3 : '';
$data['$contact.custom_value4'] = isset($contact) ? $contact->custom_value4 : '';
$data['$contact1'] = isset($contact) ? $contact->custom_value1 : '&nbsp;';
$data['$contact2'] = isset($contact) ? $contact->custom_value2 : '&nbsp;';
$data['$contact3'] = isset($contact) ? $contact->custom_value3 : '&nbsp;';
$data['$contact4'] = isset($contact) ? $contact->custom_value4 : '&nbsp;';
$data['$company.city_state_postal'] = $this->company->present()->cityStateZip($settings->city, $settings->state, $settings->postal_code, false);
$data['$company.postal_city_state'] = $this->company->present()->cityStateZip($settings->city, $settings->state, $settings->postal_code, true);
$data['$company.name'] = $this->company->present()->name();
$data['$company.city_state_postal'] = $this->company->present()->cityStateZip($settings->city, $settings->state, $settings->postal_code, false) ?: '&nbsp;';
$data['$company.postal_city_state'] = $this->company->present()->cityStateZip($settings->city, $settings->state, $settings->postal_code, true) ?: '&nbsp;';
$data['$company.name'] = $this->company->present()->name() ?: '&nbsp;';
$data['$company.company_name'] = &$data['$company.name'];
$data['$company.address1'] = $settings->address1;
$data['$company.address2'] = $settings->address2;
$data['$company.city'] = $settings->city;
$data['$company.state'] = $settings->state;
$data['$company.postal_code'] = $settings->postal_code;
$data['$company.country'] = Country::find($settings->country_id)->first()->name;
$data['$company.phone'] = $settings->phone;
$data['$company.email'] = $settings->email;
$data['$company.vat_number'] = $settings->vat_number;
$data['$company.id_number'] = $settings->id_number;
$data['$company.website'] = $settings->website;
$data['$company.address'] = $this->company->present()->address($settings);
$data['$company.address1'] = $settings->address1 ?: '&nbsp;';
$data['$company.address2'] = $settings->address2 ?: '&nbsp;';
$data['$company.city'] = $settings->city ?: '&nbsp;';
$data['$company.state'] = $settings->state ?: '&nbsp;';
$data['$company.postal_code'] = $settings->postal_code ?: '&nbsp;';
$data['$company.country'] = Country::find($settings->country_id)->first()->name ?: '&nbsp;';
$data['$company.phone'] = $settings->phone ?: '&nbsp;';
$data['$company.email'] = $settings->email ?: '&nbsp;';
$data['$company.vat_number'] = $settings->vat_number ?: '&nbsp;';
$data['$company.id_number'] = $settings->id_number ?: '&nbsp;';
$data['$company.website'] = $settings->website ?: '&nbsp;';
$data['$company.address'] = $this->company->present()->address($settings) ?: '&nbsp;';
$logo = $this->company->present()->logo($settings);
$data['$company.logo'] = "<img src='{$logo}' class='w-48' alt='logo'>";
$data['$company.logo'] = "<img src='{$logo}' class='w-48' alt='logo'>" ?: '&nbsp;';
$data['$company_logo'] = &$data['$company.logo'];
$data['$company.custom_value1'] = $this->company->custom_value1;
$data['$company.custom_value2'] = $this->company->custom_value2;
$data['$company.custom_value3'] = $this->company->custom_value3;
$data['$company.custom_value4'] = $this->company->custom_value4;
$data['$company1'] = $settings->custom_value1 ?: '&nbsp;';
$data['$company2'] = $settings->custom_value2 ?: '&nbsp;';
$data['$company3'] = $settings->custom_value3 ?: '&nbsp;';
$data['$company4'] = $settings->custom_value4 ?: '&nbsp;';
//$data['$blank'] = ;
//$data['$surcharge'] = ;
/*
@ -340,6 +424,12 @@ trait MakesInvoiceValues
$data['$amount'] = ;
$data['$amount_paid'] =;
*/
$arrKeysLength = array_map('strlen', array_keys($data));
array_multisort($arrKeysLength, SORT_DESC, $data);
// \Log::error('woop');
//\Log::error(print_r($data,1));
return $data;
}
@ -499,6 +589,26 @@ trait MakesInvoiceValues
$item->discount = $item->discount . '%';
}
}
else
$item->discount = '';
if(isset($item->tax_rate1) && $item->tax_rate1 > 0)
$item->tax_rate1 = $item->tax_rate1."%";
if(isset($item->tax_rate2) && $item->tax_rate2 > 0)
$item->tax_rate2 = $item->tax_rate2."%";
if(isset($item->tax_rate2) && $item->tax_rate2 > 0)
$item->tax_rate2 = $item->tax_rate2."%";
if(isset($item->tax_rate1) && $item->tax_rate1 == 0)
$item->tax_rate1 = '';
if(isset($item->tax_rate2) && $item->tax_rate2 == 0)
$item->tax_rate2 = '';
if(isset($item->tax_rate2) && $item->tax_rate2 == 0)
$item->tax_rate2 = '';
}

View File

@ -44,6 +44,8 @@ return [
'repository_url' => '',
'download_path' => env('SELF_UPDATER_DOWNLOAD_PATH', '/tmp'),
'private_access_token' => env('SELF_UPDATER_GITHUB_PRIVATE_ACCESS_TOKEN', ''),
'use_branch' => env('SELF_UPDATER_BRANCH_NAME', 'v2'),
],
'http' => [
'type' => 'http',

View File

@ -10,7 +10,7 @@ $factory->define(App\Models\Company::class, function (Faker $faker) {
'ip' => $faker->ipv4,
'db' => config('database.default'),
'settings' => CompanySettings::defaults(),
'custom_fields' => (object) ['custom1' => '1', 'custom2' => '2', 'custom3'=>'3'],
'custom_fields' => (object) ['invoice1' => '1', 'invoice2' => '2', 'client1'=>'3'],
// 'address1' => $faker->secondaryAddress,
// 'address2' => $faker->address,

View File

@ -1,7 +1,5 @@
<?php
use Illuminate\Http\Request;
/*
|--------------------------------------------------------------------------
| API Routes
@ -18,7 +16,8 @@ Route::middleware('auth:api')->get('/user', function (Request $request) {
});
*/
Route::group(['middleware' => ['api_secret_check']], function () {
Route::group(['middleware' => ['api_secret_check']],
function () {
Route::post('api/v1/signup', 'AccountController@store')->name('signup.submit');
Route::post('api/v1/oauth_login', 'Auth\LoginController@oauthApiLogin');
@ -44,6 +43,8 @@ Route::group(['middleware' => ['api_db', 'token_auth', 'locale'], 'prefix' => 'a
Route::get('invoices/{invoice}/{action}', 'InvoiceController@action')->name('invoices.action');
Route::get('invoice/{invitation_key}/download', 'InvoiceController@downloadPdf')->name('invoices.downloadPdf');
Route::post('invoices/bulk', 'InvoiceController@bulk')->name('invoices.bulk');
Route::resource('credits', 'CreditController');// name = (credits. index / create / show / update / destroy / edit
@ -93,7 +94,6 @@ Route::group(['middleware' => ['api_db', 'token_auth', 'locale'], 'prefix' => 'a
Route::post('users/{user}/attach_to_company', 'UserController@attach')->middleware('password_protected');
Route::delete('users/{user}/detach_from_company', 'UserController@detach')->middleware('password_protected');
Route::post('users/bulk', 'UserController@bulk')->name('users.bulk')->middleware('password_protected');
Route::post('migration/purge/{company}', 'MigrationController@purgeCompany')->middleware('password_protected');
@ -112,6 +112,8 @@ Route::group(['middleware' => ['api_db', 'token_auth', 'locale'], 'prefix' => 'a
Route::post('templates', 'TemplateController@show')->name('templates.show');
Route::post('self-update', 'SelfUpdateController@update');
/*
Route::resource('tasks', 'TaskController'); // name = (tasks. index / create / show / update / destroy / edit

View File

@ -281,6 +281,14 @@ class PaymentTest extends TestCase
$client = ClientFactory::create($this->company->id, $this->user->id);
$client->save();
factory(\App\Models\ClientContact::class)->create([
'user_id' => $this->user->id,
'client_id' => $client->id,
'company_id' =>$this->company->id,
'is_primary' => true,
]);
$this->invoice = InvoiceFactory::create($this->company->id,$this->user->id);//stub the company and user_id
$this->invoice->client_id = $client->id;

View File

@ -39,10 +39,14 @@ class InvoiceDesignTest extends TestCase
'postal_city_state',
'country',
'email',
'custom_value1',
'custom_value2',
'custom_value3',
'custom_value4',
'client1',
'client2',
'client3',
'client4',
'contact1',
'contact2',
'contact3',
'contact4',
],
'company_details' => [
'company_name',
@ -51,10 +55,10 @@ class InvoiceDesignTest extends TestCase
'website',
'email',
'phone',
'custom_value1',
'custom_value2',
'custom_value3',
'custom_value4',
'company1',
'company2',
'company3',
'company4',
],
'company_address' => [
'address1',
@ -62,10 +66,10 @@ class InvoiceDesignTest extends TestCase
'city_state_postal',
'postal_city_state',
'country',
'custom_value1',
'custom_value2',
'custom_value3',
'custom_value4',
'company1',
'company2',
'company3',
'company4',
],
'invoice_details' => [
'invoice_number',
@ -75,10 +79,14 @@ class InvoiceDesignTest extends TestCase
'balance_due',
'invoice_total',
'partial_due',
'custom_value1',
'custom_value2',
'custom_value3',
'custom_value4',
'invoice1',
'invoice2',
'invoice3',
'invoice4',
'surcharge1',
'surcharge2',
'surcharge3',
'surcharge4',
],
'table_columns' => [
'product_key',
@ -99,7 +107,7 @@ class InvoiceDesignTest extends TestCase
//\Log::error($html);
CreateInvoicePdf::dispatchNow($this->invoice, $this->invoice->company);
CreateInvoicePdf::dispatchNow($this->invoice, $this->invoice->company, $this->invoice->client->primary_contact()->first());
}