mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-05-24 02:14:21 -04:00
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:
parent
e8f19f9b63
commit
9a19f7fd4c
@ -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)
|
||||
|
@ -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,7 +414,8 @@ 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();
|
||||
// $data->email_subject_quote = EmailTemplateDefaults::emailQuoteSubject();
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -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
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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();
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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',
|
||||
|
@ -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,142 +25,78 @@ 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
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, NumberFormatter, MakesInvoiceHtml;
|
||||
class CreateInvoicePdf implements ShouldQueue {
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, NumberFormatter, MakesInvoiceHtml;
|
||||
|
||||
public $invoice;
|
||||
public $invoice;
|
||||
|
||||
public $company;
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Invoice $invoice, Company $company)
|
||||
{
|
||||
$this->invoice = $invoice;
|
||||
public $company;
|
||||
|
||||
$this->company = $company;
|
||||
}
|
||||
public $contact;
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Invoice $invoice, Company $company, ClientContact $contact) {
|
||||
$this->invoice = $invoice;
|
||||
|
||||
public function handle()
|
||||
{
|
||||
MultiDB::setDB($this->company->db);
|
||||
$this->company = $company;
|
||||
|
||||
$this->contact = $contact;
|
||||
}
|
||||
|
||||
$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'
|
||||
],
|
||||
];
|
||||
public function handle() {
|
||||
MultiDB::setDB($this->company->db);
|
||||
|
||||
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, $this->invoice->client->getSetting('invoice_variables'));
|
||||
|
||||
//get invoice design
|
||||
$html = $this->generateInvoiceHtml($designer->build($this->invoice)->getHtml(), $this->invoice, $this->contact);
|
||||
|
||||
$this->invoice->load('client');
|
||||
$path = 'public/' . $this->invoice->client->client_hash . '/invoices/';
|
||||
$file_path = $path . $this->invoice->number . '.pdf';
|
||||
//todo - move this to the client creation stage so we don't keep hitting this unnecessarily
|
||||
Storage::makeDirectory($path, 0755);
|
||||
|
||||
$modern = new Modern();
|
||||
$designer = new Designer($modern, $input_variables);
|
||||
//\Log::error($html);
|
||||
//create pdf
|
||||
$pdf = $this->makePdf(null, null, $html);
|
||||
|
||||
//get invoice design
|
||||
$html = $this->generateInvoiceHtml($designer->build($this->invoice)->getHtml(), $this->invoice);
|
||||
$path = Storage::put($file_path, $pdf);
|
||||
|
||||
//todo - move this to the client creation stage so we don't keep hitting this unnecessarily
|
||||
Storage::makeDirectory($path, 0755);
|
||||
return $path;
|
||||
}
|
||||
|
||||
\Log::error($html);
|
||||
//create pdf
|
||||
$pdf = $this->makePdf(null, null, $html);
|
||||
|
||||
$path = Storage::put($file_path, $pdf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a PDF stream
|
||||
*
|
||||
* @param string $header Header to be included in PDF
|
||||
* @param string $footer Footer to be included in PDF
|
||||
* @param string $html The HTML object to be converted into PDF
|
||||
*
|
||||
* @return string The PDF string
|
||||
*/
|
||||
private function makePdf($header, $footer, $html)
|
||||
{
|
||||
return Browsershot::html($html)
|
||||
//->showBrowserHeaderAndFooter()
|
||||
//->headerHtml($header)
|
||||
//->footerHtml($footer)
|
||||
->deviceScaleFactor(1)
|
||||
->showBackground()
|
||||
->waitUntilNetworkIdle(false)->pdf();
|
||||
//->margins(10,10,10,10)
|
||||
//->savePdf('test.pdf');
|
||||
}
|
||||
/**
|
||||
* Returns a PDF stream
|
||||
*
|
||||
* @param string $header Header to be included in PDF
|
||||
* @param string $footer Footer to be included in PDF
|
||||
* @param string $html The HTML object to be converted into PDF
|
||||
*
|
||||
* @return string The PDF string
|
||||
*/
|
||||
private function makePdf($header, $footer, $html) {
|
||||
return Browsershot::html($html)
|
||||
//->showBrowserHeaderAndFooter()
|
||||
//->headerHtml($header)
|
||||
//->footerHtml($footer)
|
||||
->deviceScaleFactor(1)
|
||||
->showBackground()
|
||||
->waitUntilNetworkIdle(true) ->pdf();
|
||||
//->margins(10,10,10,10)
|
||||
//->savePdf('test.pdf');
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -14,79 +14,70 @@ 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
|
||||
{
|
||||
use MakesDates;
|
||||
use SoftDeletes;
|
||||
use Inviteable;
|
||||
class InvoiceInvitation extends BaseModel {
|
||||
use MakesDates;
|
||||
use SoftDeletes;
|
||||
use Inviteable;
|
||||
|
||||
protected $fillable = [
|
||||
'id',
|
||||
'client_contact_id',
|
||||
];
|
||||
protected $fillable = [
|
||||
//'id',
|
||||
//'client_contact_id',
|
||||
];
|
||||
|
||||
protected $with = [
|
||||
// 'company',
|
||||
];
|
||||
protected $with = [
|
||||
// 'company',
|
||||
];
|
||||
|
||||
public function entityType()
|
||||
{
|
||||
return Invoice::class;
|
||||
}
|
||||
public function entityType() {
|
||||
return Invoice::class ;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function invoice()
|
||||
{
|
||||
return $this->belongsTo(Invoice::class)->withTrashed();
|
||||
}
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function invoice() {
|
||||
return $this->belongsTo(Invoice::class )->withTrashed();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function contact()
|
||||
{
|
||||
return $this->belongsTo(ClientContact::class, 'client_contact_id', 'id')->withTrashed();
|
||||
}
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function contact() {
|
||||
return $this->belongsTo(ClientContact::class , 'client_contact_id', 'id')->withTrashed();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo(User::class)->withTrashed();
|
||||
}
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function user() {
|
||||
return $this->belongsTo(User::class )->withTrashed();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function company()
|
||||
{
|
||||
return $this->belongsTo(Company::class);
|
||||
}
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function company() {
|
||||
return $this->belongsTo(Company::class );
|
||||
}
|
||||
|
||||
public function signatureDiv()
|
||||
{
|
||||
if (! $this->signature_base64) {
|
||||
return false;
|
||||
}
|
||||
public function signatureDiv() {
|
||||
if (!$this->signature_base64) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
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()
|
||||
{
|
||||
return $this->key;
|
||||
}
|
||||
public function getName() {
|
||||
return $this->key;
|
||||
}
|
||||
|
||||
public function markViewed()
|
||||
{
|
||||
$this->viewed_date = Carbon::now();
|
||||
$this->save();
|
||||
}
|
||||
public function markViewed() {
|
||||
$this->viewed_date = Carbon::now();
|
||||
$this->save();
|
||||
}
|
||||
}
|
||||
|
@ -11,126 +11,119 @@
|
||||
|
||||
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
|
||||
{
|
||||
use MakesHash;
|
||||
|
||||
/**
|
||||
* Gets the class name.
|
||||
*
|
||||
* @return string The class name.
|
||||
*/
|
||||
public function getClassName()
|
||||
{
|
||||
return Invoice::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the invoices
|
||||
*
|
||||
* @param array. $data The invoice data
|
||||
* @param InvoiceSum|\App\Models\Invoice $invoice The invoice
|
||||
*
|
||||
* @return Invoice|InvoiceSum|\App\Models\Invoice|null Returns the invoice object
|
||||
*/
|
||||
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;
|
||||
class InvoiceRepository extends BaseRepository {
|
||||
use MakesHash;
|
||||
|
||||
$invoice->fill($data);
|
||||
/**
|
||||
* Gets the class name.
|
||||
*
|
||||
* @return string The class name.
|
||||
*/
|
||||
public function getClassName() {
|
||||
return Invoice::class ;
|
||||
}
|
||||
|
||||
$invoice->save();
|
||||
/**
|
||||
* Saves the invoices
|
||||
*
|
||||
* @param array. $data The invoice data
|
||||
* @param InvoiceSum|\App\Models\Invoice $invoice The invoice
|
||||
*
|
||||
* @return Invoice|InvoiceSum|\App\Models\Invoice|null Returns the invoice object
|
||||
*/
|
||||
public function save($data, Invoice $invoice):?Invoice {
|
||||
|
||||
if (isset($data['client_contacts'])) {
|
||||
foreach ($data['client_contacts'] as $contact) {
|
||||
if ($contact['send_invoice'] == 1) {
|
||||
$client_contact = ClientContact::find($this->decodePrimaryKey($contact['id']));
|
||||
$client_contact->send_invoice = true;
|
||||
$client_contact->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Always carry forward the initial invoice amount this is important for tracking client balance changes later......*/
|
||||
$starting_amount = $invoice->amount;
|
||||
|
||||
if (isset($data['invitations'])) {
|
||||
$invitations = collect($data['invitations']);
|
||||
$invoice->fill($data);
|
||||
|
||||
/* Get array of Keyss which have been removed from the invitations array and soft delete each invitation */
|
||||
collect($invoice->invitations->pluck('key'))->diff($invitations->pluck('key'))->each(function ($invitation) {
|
||||
InvoiceInvitation::destroy($invitation);
|
||||
});
|
||||
$invoice->save();
|
||||
|
||||
foreach ($data['invitations'] as $invitation) {
|
||||
$inv = false;
|
||||
if (isset($data['client_contacts'])) {
|
||||
foreach ($data['client_contacts'] as $contact) {
|
||||
if ($contact['send_invoice'] == 1) {
|
||||
$client_contact = ClientContact::find($this->decodePrimaryKey($contact['id']));
|
||||
$client_contact->send_invoice = true;
|
||||
$client_contact->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (array_key_exists('key', $invitation)) {
|
||||
$inv = InvoiceInvitation::whereKey($invitation['key'])->first();
|
||||
}
|
||||
if (isset($data['invitations'])) {
|
||||
$invitations = collect($data['invitations']);
|
||||
|
||||
if (!$inv) {
|
||||
/* Get array of Keyss which have been removed from the invitations array and soft delete each invitation */
|
||||
collect($invoice->invitations->pluck('key'))->diff($invitations->pluck('key'))->each(function ($invitation) {
|
||||
InvoiceInvitation::destroy($invitation);
|
||||
});
|
||||
|
||||
$new_invitation = InvoiceInvitationFactory::create($invoice->company_id, $invoice->user_id);
|
||||
$new_invitation->fill($invitation);
|
||||
$new_invitation->invoice_id = $invoice->id;
|
||||
$new_invitation->client_contact_id = $this->decodePrimaryKey($invitation['client_contact_id']);
|
||||
$new_invitation->save();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($data['invitations'] as $invitation) {
|
||||
$inv = false;
|
||||
|
||||
/* If no invitations have been created, this is our fail safe to maintain state*/
|
||||
if ($invoice->invitations->count() == 0) {
|
||||
$invoice->service()->createInvitations();
|
||||
}
|
||||
if (array_key_exists('key', $invitation)) {
|
||||
$inv = InvoiceInvitation::whereKey($invitation['key'])->first();
|
||||
}
|
||||
|
||||
$invoice = $invoice->calc()->getInvoice();
|
||||
|
||||
$invoice->save();
|
||||
if (!$inv) {
|
||||
|
||||
$finished_amount = $invoice->amount;
|
||||
$new_invitation = InvoiceInvitationFactory::create($invoice->company_id, $invoice->user_id);
|
||||
$new_invitation->fill($invitation);
|
||||
$new_invitation->invoice_id = $invoice->id;
|
||||
$new_invitation->client_contact_id = $this->decodePrimaryKey($invitation['client_contact_id']);
|
||||
$new_invitation->save();
|
||||
|
||||
/**/
|
||||
if (($finished_amount != $starting_amount) && ($invoice->status_id != Invoice::STATUS_DRAFT)) {
|
||||
UpdateCompanyLedgerWithInvoice::dispatchNow($invoice, ($finished_amount - $starting_amount), $invoice->company);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$invoice = $invoice->service()->applyNumber()->save();
|
||||
/* If no invitations have been created, this is our fail safe to maintain state*/
|
||||
if ($invoice->invitations->count() == 0) {
|
||||
$invoice->service()->createInvitations();
|
||||
}
|
||||
|
||||
if ($invoice->company->update_products !== false) {
|
||||
UpdateOrCreateProduct::dispatch($invoice->line_items, $invoice, $invoice->company);
|
||||
}
|
||||
$invoice = $invoice->calc()->getInvoice();
|
||||
|
||||
return $invoice->fresh();
|
||||
}
|
||||
$invoice->save();
|
||||
|
||||
/**
|
||||
* Mark the invoice as sent.
|
||||
*
|
||||
* @param \App\Models\Invoice $invoice The invoice
|
||||
*
|
||||
* @return Invoice|\App\Models\Invoice|null Return the invoice object
|
||||
*/
|
||||
public function markSent(Invoice $invoice) : ?Invoice
|
||||
{
|
||||
return $invoice->service()->markSent()->save();
|
||||
}
|
||||
$finished_amount = $invoice->amount;
|
||||
|
||||
/**/
|
||||
if (($finished_amount != $starting_amount) && ($invoice->status_id != Invoice::STATUS_DRAFT)) {
|
||||
UpdateCompanyLedgerWithInvoice::dispatchNow($invoice, ($finished_amount-$starting_amount), $invoice->company);
|
||||
}
|
||||
|
||||
$invoice = $invoice->service()->applyNumber()->save();
|
||||
|
||||
if ($invoice->company->update_products !== false) {
|
||||
UpdateOrCreateProduct::dispatch($invoice->line_items, $invoice, $invoice->company);
|
||||
}
|
||||
|
||||
return $invoice->fresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the invoice as sent.
|
||||
*
|
||||
* @param \App\Models\Invoice $invoice The invoice
|
||||
*
|
||||
* @return Invoice|\App\Models\Invoice|null Return the invoice object
|
||||
*/
|
||||
public function markSent(Invoice $invoice):?Invoice {
|
||||
return $invoice->service()->markSent()->save();
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 ?: ' ';
|
||||
$data['$invoice.date'] = &$data['$date'];
|
||||
$data['$due_date'] = $this->due_date;
|
||||
$data['$due_date'] = $this->due_date ?: ' ';
|
||||
$data['$invoice.due_date'] = &$data['$due_date'];
|
||||
$data['$number'] = $this->number;
|
||||
$data['$number'] = $this->number ?: ' ';
|
||||
$data['$invoice.number'] = &$data['$number'];
|
||||
$data['$invoice_number'] = &$data['$number'];
|
||||
$data['$po_number'] = $this->po_number;
|
||||
$data['$po_number'] = $this->po_number ?: ' ';
|
||||
$data['$invoice.po_number'] = &$data['$po_number'];
|
||||
$data['$line_taxes'] = $this->makeLineTaxes();
|
||||
$data['$line_taxes'] = $this->makeLineTaxes() ?: ' ';
|
||||
$data['$invoice.line_taxes'] = &$data['$line_taxes'];
|
||||
$data['$total_taxes'] = $this->makeTotalTaxes();
|
||||
$data['$total_taxes'] = $this->makeTotalTaxes() ?: ' ';
|
||||
$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) ?: ' ';
|
||||
$data['$invoice.discount'] = &$data['$discount'];
|
||||
$data['$subtotal'] = Number::formatMoney($this->calc()->getSubTotal(), $this->client);
|
||||
$data['$subtotal'] = Number::formatMoney($this->calc()->getSubTotal(), $this->client) ?: ' ';
|
||||
$data['$invoice.subtotal'] = &$data['$subtotal'];
|
||||
$data['$balance_due'] = Number::formatMoney($this->balance, $this->client);
|
||||
$data['$balance_due'] = Number::formatMoney($this->balance, $this->client) ?: ' ';
|
||||
$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) ?: ' ';
|
||||
$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) ?: ' ';
|
||||
$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) ?: ' ';
|
||||
$data['$invoice.balance'] = &$data['$balance'];
|
||||
$data['$taxes'] = Number::formatMoney($this->calc()->getItemTotalTaxes(), $this->client);
|
||||
$data['$taxes'] = Number::formatMoney($this->calc()->getItemTotalTaxes(), $this->client) ?: ' ';
|
||||
$data['$invoice.taxes'] = &$data['$taxes'];
|
||||
$data['$terms'] = $this->terms;
|
||||
$data['$terms'] = $this->terms ?: ' ';
|
||||
$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 ?: ' ';
|
||||
$data['$invoice2'] = $this->custom_value2 ?: ' ';
|
||||
$data['$invoice3'] = $this->custom_value3 ?: ' ';
|
||||
$data['$invoice4'] = $this->custom_value4 ?: ' ';
|
||||
$data['$invoice.public_notes'] = $this->public_notes ?: ' ';
|
||||
// $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 ?: ' ';
|
||||
$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 ?: ' ';
|
||||
$data['$client2'] = $this->client->custom_value2 ?: ' ';
|
||||
$data['$client3'] = $this->client->custom_value3 ?: ' ';
|
||||
$data['$client4'] = $this->client->custom_value4 ?: ' ';
|
||||
$data['$client_name'] = $this->present()->clientName() ?: ' ';
|
||||
$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 ?: ' ';
|
||||
$data['$address2'] = $this->client->address2 ?: ' ';
|
||||
$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() ?: ' ';
|
||||
$data['$id_number'] = $this->client->id_number ?: ' ';
|
||||
$data['$client.id_number'] = &$data['$id_number'];
|
||||
$data['$vat_number'] = $this->client->vat_number;
|
||||
$data['$vat_number'] = $this->client->vat_number ?: ' ';
|
||||
$data['$client.vat_number'] = &$data['$vat_number'];
|
||||
$data['$website'] = $this->client->present()->website();
|
||||
$data['$website'] = $this->client->present()->website() ?: ' ';
|
||||
$data['$client.website'] = &$data['$website'];
|
||||
$data['$phone'] = $this->client->present()->phone();
|
||||
$data['$phone'] = $this->client->present()->phone() ?: ' ';
|
||||
$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) ?: ' ';
|
||||
$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) ?: ' ';
|
||||
$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 : ' ';
|
||||
$data['$contact2'] = isset($contact) ? $contact->custom_value2 : ' ';
|
||||
$data['$contact3'] = isset($contact) ? $contact->custom_value3 : ' ';
|
||||
$data['$contact4'] = isset($contact) ? $contact->custom_value4 : ' ';
|
||||
|
||||
$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) ?: ' ';
|
||||
$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.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 ?: ' ';
|
||||
$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) ?: ' ';
|
||||
|
||||
$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'>" ?: ' ';
|
||||
$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 ?: ' ';
|
||||
$data['$company2'] = $settings->custom_value2 ?: ' ';
|
||||
$data['$company3'] = $settings->custom_value3 ?: ' ';
|
||||
$data['$company4'] = $settings->custom_value4 ?: ' ';
|
||||
//$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 = '';
|
||||
}
|
||||
|
||||
|
||||
|
@ -2,124 +2,126 @@
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default source repository type
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The default source repository type you want to pull your updates from.
|
||||
|
|
||||
*/
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default source repository type
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The default source repository type you want to pull your updates from.
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('SELF_UPDATER_SOURCE', 'github'),
|
||||
'default' => env('SELF_UPDATER_SOURCE', 'github'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Version installed
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Set this to the version of your software installed on your system.
|
||||
|
|
||||
*/
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Version installed
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Set this to the version of your software installed on your system.
|
||||
|
|
||||
*/
|
||||
|
||||
'version_installed' => env('SELF_UPDATER_VERSION_INSTALLED', ''),
|
||||
'version_installed' => env('SELF_UPDATER_VERSION_INSTALLED', ''),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Repository types
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| A repository can be of different types, which can be specified here.
|
||||
| Current options:
|
||||
| - github
|
||||
| - http
|
||||
|
|
||||
*/
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Repository types
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| A repository can be of different types, which can be specified here.
|
||||
| Current options:
|
||||
| - github
|
||||
| - http
|
||||
|
|
||||
*/
|
||||
|
||||
'repository_types' => [
|
||||
'github' => [
|
||||
'type' => 'github',
|
||||
'repository_vendor' => env('SELF_UPDATER_REPO_VENDOR', ''),
|
||||
'repository_name' => env('SELF_UPDATER_REPO_NAME', ''),
|
||||
'repository_url' => '',
|
||||
'download_path' => env('SELF_UPDATER_DOWNLOAD_PATH', '/tmp'),
|
||||
'private_access_token' => env('SELF_UPDATER_GITHUB_PRIVATE_ACCESS_TOKEN', ''),
|
||||
],
|
||||
'http' => [
|
||||
'type' => 'http',
|
||||
'repository_url' => env('SELF_UPDATER_REPO_URL', ''),
|
||||
'pkg_filename_format' => env('SELF_UPDATER_PKG_FILENAME_FORMAT', 'v_VERSION_'),
|
||||
'download_path' => env('SELF_UPDATER_DOWNLOAD_PATH', '/tmp'),
|
||||
'private_access_token' => env('SELF_UPDATER_HTTP_PRIVATE_ACCESS_TOKEN', ''),
|
||||
],
|
||||
],
|
||||
'repository_types' => [
|
||||
'github' => [
|
||||
'type' => 'github',
|
||||
'repository_vendor' => env('SELF_UPDATER_REPO_VENDOR', ''),
|
||||
'repository_name' => env('SELF_UPDATER_REPO_NAME', ''),
|
||||
'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'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Exclude folders from update
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Specifiy folders which should not be updated and will be skipped during the
|
||||
| update process.
|
||||
|
|
||||
| Here's already a list of good examples to skip. You may want to keep those.
|
||||
|
|
||||
*/
|
||||
],
|
||||
'http' => [
|
||||
'type' => 'http',
|
||||
'repository_url' => env('SELF_UPDATER_REPO_URL', ''),
|
||||
'pkg_filename_format' => env('SELF_UPDATER_PKG_FILENAME_FORMAT', 'v_VERSION_'),
|
||||
'download_path' => env('SELF_UPDATER_DOWNLOAD_PATH', '/tmp'),
|
||||
'private_access_token' => env('SELF_UPDATER_HTTP_PRIVATE_ACCESS_TOKEN', ''),
|
||||
],
|
||||
],
|
||||
|
||||
'exclude_folders' => [
|
||||
'node_modules',
|
||||
'bootstrap/cache',
|
||||
'bower',
|
||||
'storage/app',
|
||||
'storage/framework',
|
||||
'storage/logs',
|
||||
'storage/self-update',
|
||||
'vendor',
|
||||
],
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Exclude folders from update
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Specifiy folders which should not be updated and will be skipped during the
|
||||
| update process.
|
||||
|
|
||||
| Here's already a list of good examples to skip. You may want to keep those.
|
||||
|
|
||||
*/
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Event Logging
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Configure if fired events should be logged
|
||||
|
|
||||
*/
|
||||
'exclude_folders' => [
|
||||
'node_modules',
|
||||
'bootstrap/cache',
|
||||
'bower',
|
||||
'storage/app',
|
||||
'storage/framework',
|
||||
'storage/logs',
|
||||
'storage/self-update',
|
||||
'vendor',
|
||||
],
|
||||
|
||||
'log_events' => env('SELF_UPDATER_LOG_EVENTS', false),
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Event Logging
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Configure if fired events should be logged
|
||||
|
|
||||
*/
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Mail To Settings
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Configure if fired events should be logged
|
||||
|
|
||||
*/
|
||||
'log_events' => env('SELF_UPDATER_LOG_EVENTS', false),
|
||||
|
||||
'mail_to' => [
|
||||
'address' => env('SELF_UPDATER_MAILTO_ADDRESS', ''),
|
||||
'name' => env('SELF_UPDATER_MAILTO_NAME', ''),
|
||||
'subject_update_available' => env('SELF_UPDATER_MAILTO_UPDATE_AVAILABLE_SUBJECT', 'Update available'),
|
||||
'subject_update_succeeded' => env('SELF_UPDATER_MAILTO_UPDATE_SUCCEEDED_SUBJECT', 'Update succeeded'),
|
||||
],
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Mail To Settings
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Configure if fired events should be logged
|
||||
|
|
||||
*/
|
||||
|
||||
/*
|
||||
|---------------------------------------------------------------------------
|
||||
| Register custom artisan commands
|
||||
|---------------------------------------------------------------------------
|
||||
*/
|
||||
'mail_to' => [
|
||||
'address' => env('SELF_UPDATER_MAILTO_ADDRESS', ''),
|
||||
'name' => env('SELF_UPDATER_MAILTO_NAME', ''),
|
||||
'subject_update_available' => env('SELF_UPDATER_MAILTO_UPDATE_AVAILABLE_SUBJECT', 'Update available'),
|
||||
'subject_update_succeeded' => env('SELF_UPDATER_MAILTO_UPDATE_SUCCEEDED_SUBJECT', 'Update succeeded'),
|
||||
],
|
||||
|
||||
'artisan_commands' => [
|
||||
'pre_update' => [
|
||||
//'command:signature' => [
|
||||
// 'class' => Command class
|
||||
// 'params' => []
|
||||
//]
|
||||
],
|
||||
'post_update' => [
|
||||
/*
|
||||
|---------------------------------------------------------------------------
|
||||
| Register custom artisan commands
|
||||
|---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
],
|
||||
],
|
||||
'artisan_commands' => [
|
||||
'pre_update' => [
|
||||
//'command:signature' => [
|
||||
// 'class' => Command class
|
||||
// 'params' => []
|
||||
//]
|
||||
],
|
||||
'post_update' => [
|
||||
|
||||
],
|
||||
],
|
||||
|
||||
];
|
||||
|
@ -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,
|
||||
|
152
routes/api.php
152
routes/api.php
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| API Routes
|
||||
@ -14,120 +12,124 @@ use Illuminate\Http\Request;
|
||||
|
||||
|
||||
Route::middleware('auth:api')->get('/user', function (Request $request) {
|
||||
return $request->user();
|
||||
return $request->user();
|
||||
});
|
||||
*/
|
||||
*/
|
||||
|
||||
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');
|
||||
Route::post('api/v1/signup', 'AccountController@store')->name('signup.submit');
|
||||
Route::post('api/v1/oauth_login', 'Auth\LoginController@oauthApiLogin');
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
Route::group(['api_secret_check', 'email_db'], function () {
|
||||
|
||||
Route::post('api/v1/login', 'Auth\LoginController@apiLogin')->name('login.submit');
|
||||
Route::post('api/v1/reset_password', 'Auth\ForgotPasswordController@sendResetLinkEmail')->name('password.reset');
|
||||
Route::post('api/v1/login', 'Auth\LoginController@apiLogin')->name('login.submit');
|
||||
Route::post('api/v1/reset_password', 'Auth\ForgotPasswordController@sendResetLinkEmail')->name('password.reset');
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
Route::group(['middleware' => ['api_db', 'token_auth', 'locale'], 'prefix' => 'api/v1', 'as' => 'api.'], function () {
|
||||
|
||||
Route::resource('activities', 'ActivityController'); // name = (clients. index / create / show / update / destroy / edit
|
||||
Route::resource('activities', 'ActivityController');// name = (clients. index / create / show / update / destroy / edit
|
||||
|
||||
Route::resource('clients', 'ClientController'); // name = (clients. index / create / show / update / destroy / edit
|
||||
Route::resource('clients', 'ClientController');// name = (clients. index / create / show / update / destroy / edit
|
||||
|
||||
Route::post('clients/bulk', 'ClientController@bulk')->name('clients.bulk');
|
||||
Route::post('clients/bulk', 'ClientController@bulk')->name('clients.bulk');
|
||||
|
||||
Route::resource('invoices', 'InvoiceController'); // name = (invoices. index / create / show / update / destroy / edit
|
||||
|
||||
Route::get('invoices/{invoice}/{action}', 'InvoiceController@action')->name('invoices.action');
|
||||
|
||||
Route::post('invoices/bulk', 'InvoiceController@bulk')->name('invoices.bulk');
|
||||
Route::resource('invoices', 'InvoiceController');// name = (invoices. index / create / show / update / destroy / edit
|
||||
|
||||
Route::resource('credits', 'CreditController'); // name = (credits. index / create / show / update / destroy / edit
|
||||
Route::get('invoices/{invoice}/{action}', 'InvoiceController@action')->name('invoices.action');
|
||||
|
||||
Route::get('credits/{credit}/{action}', 'CreditController@action')->name('credits.action');
|
||||
Route::get('invoice/{invitation_key}/download', 'InvoiceController@downloadPdf')->name('invoices.downloadPdf');
|
||||
|
||||
Route::post('credits/bulk', 'CreditController@bulk')->name('credits.bulk');
|
||||
Route::post('invoices/bulk', 'InvoiceController@bulk')->name('invoices.bulk');
|
||||
|
||||
Route::resource('products', 'ProductController'); // name = (products. index / create / show / update / destroy / edit
|
||||
Route::resource('credits', 'CreditController');// name = (credits. index / create / show / update / destroy / edit
|
||||
|
||||
Route::post('products/bulk', 'ProductController@bulk')->name('products.bulk');
|
||||
Route::get('credits/{credit}/{action}', 'CreditController@action')->name('credits.action');
|
||||
|
||||
Route::resource('quotes', 'QuoteController'); // name = (quotes. index / create / show / update / destroy / edit
|
||||
Route::post('credits/bulk', 'CreditController@bulk')->name('credits.bulk');
|
||||
|
||||
Route::post('quotes/bulk', 'QuoteController@bulk')->name('quotes.bulk');
|
||||
Route::resource('products', 'ProductController');// name = (products. index / create / show / update / destroy / edit
|
||||
|
||||
Route::resource('recurring_invoices', 'RecurringInvoiceController'); // name = (recurring_invoices. index / create / show / update / destroy / edit
|
||||
Route::post('products/bulk', 'ProductController@bulk')->name('products.bulk');
|
||||
|
||||
Route::post('recurring_invoices/bulk', 'RecurringInvoiceController@bulk')->name('recurring_invoices.bulk');
|
||||
Route::resource('quotes', 'QuoteController');// name = (quotes. index / create / show / update / destroy / edit
|
||||
|
||||
Route::resource('recurring_quotes', 'RecurringQuoteController'); // name = (recurring_invoices. index / create / show / update / destroy / edit
|
||||
Route::post('quotes/bulk', 'QuoteController@bulk')->name('quotes.bulk');
|
||||
|
||||
Route::post('recurring_quotes/bulk', 'RecurringQuoteController@bulk')->name('recurring_quotes.bulk');
|
||||
Route::resource('recurring_invoices', 'RecurringInvoiceController');// name = (recurring_invoices. index / create / show / update / destroy / edit
|
||||
|
||||
Route::resource('expenses', 'ExpenseController'); // name = (expenses. index / create / show / update / destroy / edit
|
||||
Route::post('recurring_invoices/bulk', 'RecurringInvoiceController@bulk')->name('recurring_invoices.bulk');
|
||||
|
||||
Route::post('expenses/bulk', 'ExpenseController@bulk')->name('expenses.bulk');
|
||||
Route::resource('recurring_quotes', 'RecurringQuoteController');// name = (recurring_invoices. index / create / show / update / destroy / edit
|
||||
|
||||
Route::resource('vendors', 'VendorController'); // name = (vendors. index / create / show / update / destroy / edit
|
||||
Route::post('recurring_quotes/bulk', 'RecurringQuoteController@bulk')->name('recurring_quotes.bulk');
|
||||
|
||||
Route::post('vendors/bulk', 'VendorController@bulk')->name('vendors.bulk');
|
||||
Route::resource('expenses', 'ExpenseController');// name = (expenses. index / create / show / update / destroy / edit
|
||||
|
||||
Route::resource('client_statement', 'ClientStatementController@statement'); // name = (client_statement. index / create / show / update / destroy / edit
|
||||
Route::post('expenses/bulk', 'ExpenseController@bulk')->name('expenses.bulk');
|
||||
|
||||
Route::resource('payments', 'PaymentController'); // name = (payments. index / create / show / update / destroy / edit
|
||||
Route::resource('vendors', 'VendorController');// name = (vendors. index / create / show / update / destroy / edit
|
||||
|
||||
Route::post('payments/refund', 'PaymentController@refund')->name('payments.refund');
|
||||
Route::post('vendors/bulk', 'VendorController@bulk')->name('vendors.bulk');
|
||||
|
||||
Route::post('payments/bulk', 'PaymentController@bulk')->name('payments.bulk');
|
||||
Route::resource('client_statement', 'ClientStatementController@statement');// name = (client_statement. index / create / show / update / destroy / edit
|
||||
|
||||
Route::post('migrate', 'Migration\MigrateController@index')->name('migrate.start');
|
||||
Route::resource('payments', 'PaymentController');// name = (payments. index / create / show / update / destroy / edit
|
||||
|
||||
// Route::resource('users', 'UserController')->middleware('password_protected'); // name = (users. index / create / show / update / destroy / edit
|
||||
Route::get('users', 'UserController@index');
|
||||
Route::put('users/{user}', 'UserController@update')->middleware('password_protected');
|
||||
Route::post('users', 'UserController@store')->middleware('password_protected');
|
||||
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('payments/refund', 'PaymentController@refund')->name('payments.refund');
|
||||
|
||||
Route::post('payments/bulk', 'PaymentController@bulk')->name('payments.bulk');
|
||||
|
||||
Route::post('migrate', 'Migration\MigrateController@index')->name('migrate.start');
|
||||
|
||||
// Route::resource('users', 'UserController')->middleware('password_protected'); // name = (users. index / create / show / update / destroy / edit
|
||||
Route::get('users', 'UserController@index');
|
||||
Route::put('users/{user}', 'UserController@update')->middleware('password_protected');
|
||||
Route::post('users', 'UserController@store')->middleware('password_protected');
|
||||
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');
|
||||
Route::post('migration/purge_save_settings/{company}', 'MigrationController@purgeCompanySaveSettings')->middleware('password_protected');
|
||||
Route::post('migration/start', 'MigrationController@startMigration')->middleware('password_protected');
|
||||
|
||||
Route::resource('companies', 'CompanyController');// name = (companies. index / create / show / update / destroy / edit
|
||||
|
||||
Route::resource('company_gateways', 'CompanyGatewayController');
|
||||
|
||||
Route::resource('group_settings', 'GroupSettingController');
|
||||
|
||||
Route::resource('tax_rates', 'TaxRateController');// name = (tasks. index / create / show / update / destroy / edit
|
||||
|
||||
Route::post('refresh', 'Auth\LoginController@refresh');
|
||||
|
||||
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
|
||||
|
||||
Route::post('tasks/bulk', 'TaskController@bulk')->name('tasks.bulk');
|
||||
|
||||
|
||||
Route::post('users/bulk', 'UserController@bulk')->name('users.bulk')->middleware('password_protected');
|
||||
Route::resource('credits', 'CreditController'); // name = (credits. index / create / show / update / destroy / edit
|
||||
|
||||
Route::post('migration/purge/{company}', 'MigrationController@purgeCompany')->middleware('password_protected');
|
||||
Route::post('migration/purge_save_settings/{company}', 'MigrationController@purgeCompanySaveSettings')->middleware('password_protected');
|
||||
Route::post('migration/start', 'MigrationController@startMigration')->middleware('password_protected');
|
||||
|
||||
Route::resource('companies', 'CompanyController'); // name = (companies. index / create / show / update / destroy / edit
|
||||
|
||||
Route::resource('company_gateways', 'CompanyGatewayController');
|
||||
|
||||
Route::resource('group_settings', 'GroupSettingController');
|
||||
|
||||
Route::resource('tax_rates', 'TaxRateController'); // name = (tasks. index / create / show / update / destroy / edit
|
||||
|
||||
Route::post('refresh', 'Auth\LoginController@refresh');
|
||||
|
||||
Route::post('templates', 'TemplateController@show')->name('templates.show');
|
||||
|
||||
/*
|
||||
Route::resource('tasks', 'TaskController'); // name = (tasks. index / create / show / update / destroy / edit
|
||||
|
||||
Route::post('tasks/bulk', 'TaskController@bulk')->name('tasks.bulk');
|
||||
|
||||
|
||||
Route::resource('credits', 'CreditController'); // name = (credits. index / create / show / update / destroy / edit
|
||||
|
||||
Route::post('credits/bulk', 'CreditController@bulk')->name('credits.bulk');
|
||||
Route::post('credits/bulk', 'CreditController@bulk')->name('credits.bulk');
|
||||
|
||||
|
||||
|
||||
|
||||
Route::get('settings', 'SettingsController@index')->name('user.settings');
|
||||
*/
|
||||
Route::post('support/messages/send', 'Support\Messages\SendingController');
|
||||
});
|
||||
Route::get('settings', 'SettingsController@index')->name('user.settings');
|
||||
*/
|
||||
Route::post('support/messages/send', 'Support\Messages\SendingController');
|
||||
});
|
||||
|
||||
Route::fallback('BaseController@notFound');
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user