mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
Merge pull request #7598 from turbo124/v5-develop
Fixes for Purchase Orders
This commit is contained in:
commit
0b717aceac
@ -25,6 +25,9 @@ class CompanySettings extends BaseSettings
|
|||||||
/*Invoice*/
|
/*Invoice*/
|
||||||
public $auto_archive_invoice = false; // @implemented
|
public $auto_archive_invoice = false; // @implemented
|
||||||
|
|
||||||
|
public $qr_iban = ''; //@implemented
|
||||||
|
public $besr_id = ''; //@implemented
|
||||||
|
|
||||||
public $lock_invoices = 'off'; //off,when_sent,when_paid //@implemented
|
public $lock_invoices = 'off'; //off,when_sent,when_paid //@implemented
|
||||||
|
|
||||||
public $enable_client_portal_tasks = false; //@ben to implement
|
public $enable_client_portal_tasks = false; //@ben to implement
|
||||||
@ -289,6 +292,8 @@ class CompanySettings extends BaseSettings
|
|||||||
public $auto_archive_invoice_cancelled = false;
|
public $auto_archive_invoice_cancelled = false;
|
||||||
|
|
||||||
public static $casts = [
|
public static $casts = [
|
||||||
|
'besr_id' => 'string',
|
||||||
|
'qr_iban' => 'string',
|
||||||
'email_subject_purchase_order' => 'string',
|
'email_subject_purchase_order' => 'string',
|
||||||
'email_template_purchase_order' => 'string',
|
'email_template_purchase_order' => 'string',
|
||||||
'require_purchase_order_signature' => 'bool',
|
'require_purchase_order_signature' => 'bool',
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
namespace App\Factory;
|
namespace App\Factory;
|
||||||
|
|
||||||
|
use App\Models\CompanyUser;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
|
||||||
class UserFactory
|
class UserFactory
|
||||||
|
146
app/Helpers/SwissQr/SwissQrGenerator.php
Normal file
146
app/Helpers/SwissQr/SwissQrGenerator.php
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Helpers\SwissQr;
|
||||||
|
|
||||||
|
use App\Models\Client;
|
||||||
|
use App\Models\Company;
|
||||||
|
use App\Models\Invoice;
|
||||||
|
use Sprain\SwissQrBill as QrBill;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SwissQrGenerator.
|
||||||
|
*/
|
||||||
|
class SwissQrGenerator
|
||||||
|
{
|
||||||
|
|
||||||
|
protected Company $company;
|
||||||
|
|
||||||
|
protected Invoice $invoice;
|
||||||
|
|
||||||
|
protected Client $client;
|
||||||
|
|
||||||
|
public function __construct(Invoice $invoice, Company $company)
|
||||||
|
{
|
||||||
|
$this->company = $company;
|
||||||
|
|
||||||
|
$this->invoice = $invoice;
|
||||||
|
|
||||||
|
$this->client = $invoice->client;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function calcDueAmount()
|
||||||
|
{
|
||||||
|
if($this->invoice->partial > 0)
|
||||||
|
return $this->invoice->partial;
|
||||||
|
|
||||||
|
if($this->invoice->status_id == Invoice::STATUS_DRAFT)
|
||||||
|
return $this->invoice->amount;
|
||||||
|
|
||||||
|
return $this->invoice->balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
|
||||||
|
// This is an example how to create a typical qr bill:
|
||||||
|
// - with reference number
|
||||||
|
// - with known debtor
|
||||||
|
// - with specified amount
|
||||||
|
// - with human-readable additional information
|
||||||
|
// - using your QR-IBAN
|
||||||
|
//
|
||||||
|
// Likely the most common use-case in the business world.
|
||||||
|
|
||||||
|
// Create a new instance of QrBill, containing default headers with fixed values
|
||||||
|
$qrBill = QrBill\QrBill::create();
|
||||||
|
|
||||||
|
|
||||||
|
// Add creditor information
|
||||||
|
// Who will receive the payment and to which bank account?
|
||||||
|
$qrBill->setCreditor(
|
||||||
|
QrBill\DataGroup\Element\CombinedAddress::create(
|
||||||
|
$this->company->present()->name(),
|
||||||
|
$this->company->present()->address1(),
|
||||||
|
$this->company->present()->getCompanyCityState(),
|
||||||
|
'CH'
|
||||||
|
));
|
||||||
|
|
||||||
|
$qrBill->setCreditorInformation(
|
||||||
|
QrBill\DataGroup\Element\CreditorInformation::create(
|
||||||
|
$this->company->present()->qr_iban() ?: '' // This is a special QR-IBAN. Classic IBANs will not be valid here.
|
||||||
|
));
|
||||||
|
|
||||||
|
// Add debtor information
|
||||||
|
// Who has to pay the invoice? This part is optional.
|
||||||
|
//
|
||||||
|
// Notice how you can use two different styles of addresses: CombinedAddress or StructuredAddress
|
||||||
|
// They are interchangeable for creditor as well as debtor.
|
||||||
|
$qrBill->setUltimateDebtor(
|
||||||
|
QrBill\DataGroup\Element\StructuredAddress::createWithStreet(
|
||||||
|
$this->client->present()->name(),
|
||||||
|
$this->client->address1 ?: '',
|
||||||
|
$this->client->address2 ?: '',
|
||||||
|
$this->client->postal_code ?: '',
|
||||||
|
$this->client->city ?: '',
|
||||||
|
'CH'
|
||||||
|
));
|
||||||
|
|
||||||
|
// Add payment amount information
|
||||||
|
// What amount is to be paid?
|
||||||
|
$qrBill->setPaymentAmountInformation(
|
||||||
|
QrBill\DataGroup\Element\PaymentAmountInformation::create(
|
||||||
|
'CHF',
|
||||||
|
$this->calcDueAmount()
|
||||||
|
));
|
||||||
|
|
||||||
|
// Add payment reference
|
||||||
|
// This is what you will need to identify incoming payments.
|
||||||
|
$referenceNumber = QrBill\Reference\QrPaymentReferenceGenerator::generate(
|
||||||
|
$this->company->present()->besr_id() ?: '', // You receive this number from your bank (BESR-ID). Unless your bank is PostFinance, in that case use NULL.
|
||||||
|
$this->invoice->number // A number to match the payment with your internal data, e.g. an invoice number
|
||||||
|
);
|
||||||
|
|
||||||
|
$qrBill->setPaymentReference(
|
||||||
|
QrBill\DataGroup\Element\PaymentReference::create(
|
||||||
|
QrBill\DataGroup\Element\PaymentReference::TYPE_QR,
|
||||||
|
$referenceNumber
|
||||||
|
));
|
||||||
|
|
||||||
|
// Optionally, add some human-readable information about what the bill is for.
|
||||||
|
$qrBill->setAdditionalInformation(
|
||||||
|
QrBill\DataGroup\Element\AdditionalInformation::create(
|
||||||
|
$this->invoice->public_notes ?: ''
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// Now get the QR code image and save it as a file.
|
||||||
|
try {
|
||||||
|
// $qrBill->getQrCode()->writeFile(__DIR__ . '/qr.png');
|
||||||
|
// $qrBill->getQrCode()->writeFile(__DIR__ . '/qr.svg');
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
foreach($qrBill->getViolations() as $key => $violation) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// return $e->getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
$output = new QrBill\PaymentPart\Output\HtmlOutput\HtmlOutput($qrBill, 'en');
|
||||||
|
|
||||||
|
$html = $output
|
||||||
|
->setPrintable(false)
|
||||||
|
->getPaymentPart();
|
||||||
|
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
470
app/Http/Controllers/PreviewPurchaseOrderController.php
Normal file
470
app/Http/Controllers/PreviewPurchaseOrderController.php
Normal file
@ -0,0 +1,470 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\DataMapper\Analytics\LivePreview;
|
||||||
|
use App\Factory\CreditFactory;
|
||||||
|
use App\Factory\InvoiceFactory;
|
||||||
|
use App\Factory\PurchaseOrderFactory;
|
||||||
|
use App\Factory\QuoteFactory;
|
||||||
|
use App\Factory\RecurringInvoiceFactory;
|
||||||
|
use App\Http\Requests\Invoice\StoreInvoiceRequest;
|
||||||
|
use App\Http\Requests\Preview\PreviewInvoiceRequest;
|
||||||
|
use App\Http\Requests\Preview\PreviewPurchaseOrderRequest;
|
||||||
|
use App\Jobs\Util\PreviewPdf;
|
||||||
|
use App\Libraries\MultiDB;
|
||||||
|
use App\Models\Client;
|
||||||
|
use App\Models\ClientContact;
|
||||||
|
use App\Models\Credit;
|
||||||
|
use App\Models\Invoice;
|
||||||
|
use App\Models\InvoiceInvitation;
|
||||||
|
use App\Models\PurchaseOrder;
|
||||||
|
use App\Models\PurchaseOrderInvitation;
|
||||||
|
use App\Models\Quote;
|
||||||
|
use App\Models\RecurringInvoice;
|
||||||
|
use App\Models\Vendor;
|
||||||
|
use App\Models\VendorContact;
|
||||||
|
use App\Repositories\CreditRepository;
|
||||||
|
use App\Repositories\InvoiceRepository;
|
||||||
|
use App\Repositories\PurchaseOrderRepository;
|
||||||
|
use App\Repositories\QuoteRepository;
|
||||||
|
use App\Repositories\RecurringInvoiceRepository;
|
||||||
|
use App\Services\PdfMaker\Design as PdfDesignModel;
|
||||||
|
use App\Services\PdfMaker\Design as PdfMakerDesign;
|
||||||
|
use App\Services\PdfMaker\Design;
|
||||||
|
use App\Services\PdfMaker\PdfMaker;
|
||||||
|
use App\Utils\HostedPDF\NinjaPdf;
|
||||||
|
use App\Utils\HtmlEngine;
|
||||||
|
use App\Utils\Ninja;
|
||||||
|
use App\Utils\PhantomJS\Phantom;
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use App\Utils\Traits\MakesInvoiceHtml;
|
||||||
|
use App\Utils\Traits\Pdf\PageNumbering;
|
||||||
|
use App\Utils\VendorHtmlEngine;
|
||||||
|
use Illuminate\Support\Facades\App;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Lang;
|
||||||
|
use Illuminate\Support\Facades\Response;
|
||||||
|
use Turbo124\Beacon\Facades\LightLogs;
|
||||||
|
|
||||||
|
class PreviewPurchaseOrderController extends BaseController
|
||||||
|
{
|
||||||
|
use MakesHash;
|
||||||
|
use MakesInvoiceHtml;
|
||||||
|
use PageNumbering;
|
||||||
|
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a template filled with entity variables.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\Response
|
||||||
|
*
|
||||||
|
* @OA\Post(
|
||||||
|
* path="/api/v1/preview/purchase_order",
|
||||||
|
* operationId="getPreviewPurchaseOrder",
|
||||||
|
* tags={"preview"},
|
||||||
|
* summary="Returns a pdf preview for purchase order",
|
||||||
|
* description="Returns a pdf preview for purchase order.",
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="The pdf response",
|
||||||
|
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=422,
|
||||||
|
* description="Validation error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
|
||||||
|
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="Unexpected Error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Error"),
|
||||||
|
* ),
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function show()
|
||||||
|
{
|
||||||
|
if (request()->has('entity') &&
|
||||||
|
request()->has('entity_id') &&
|
||||||
|
! empty(request()->input('entity')) &&
|
||||||
|
! empty(request()->input('entity_id')) &&
|
||||||
|
request()->has('body')) {
|
||||||
|
|
||||||
|
$design_object = json_decode(json_encode(request()->input('design')));
|
||||||
|
|
||||||
|
if (! is_object($design_object)) {
|
||||||
|
return response()->json(['message' => ctrans('texts.invalid_design_object')], 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$entity_obj = PurchaseOrder::whereId($this->decodePrimaryKey(request()->input('entity_id')))->company()->first();
|
||||||
|
|
||||||
|
if (! $entity_obj) {
|
||||||
|
return $this->blankEntity();
|
||||||
|
}
|
||||||
|
|
||||||
|
App::forgetInstance('translator');
|
||||||
|
$t = app('translator');
|
||||||
|
App::setLocale($entity_obj->company->locale());
|
||||||
|
$t->replace(Ninja::transformTranslations($entity_obj->company->settings));
|
||||||
|
|
||||||
|
$html = new VendorHtmlEngine($entity_obj->invitations()->first());
|
||||||
|
|
||||||
|
$design_namespace = 'App\Services\PdfMaker\Designs\\'.request()->design['name'];
|
||||||
|
|
||||||
|
$design_class = new $design_namespace();
|
||||||
|
|
||||||
|
$state = [
|
||||||
|
'template' => $design_class->elements([
|
||||||
|
'client' => null,
|
||||||
|
'vendor' => $entity_obj->vendor,
|
||||||
|
'entity' => $entity_obj,
|
||||||
|
'pdf_variables' => (array) $entity_obj->company->settings->pdf_variables,
|
||||||
|
'variables' => $html->generateLabelsAndValues(),
|
||||||
|
]),
|
||||||
|
'variables' => $html->generateLabelsAndValues(),
|
||||||
|
'process_markdown' => $entity_obj->company->markdown_enabled,
|
||||||
|
];
|
||||||
|
|
||||||
|
$design = new Design(request()->design['name']);
|
||||||
|
$maker = new PdfMaker($state);
|
||||||
|
|
||||||
|
$maker
|
||||||
|
->design($design)
|
||||||
|
->build();
|
||||||
|
|
||||||
|
if (request()->query('html') == 'true') {
|
||||||
|
return $maker->getCompiledHTML();
|
||||||
|
}
|
||||||
|
|
||||||
|
//if phantom js...... inject here..
|
||||||
|
if (config('ninja.phantomjs_pdf_generation') || config('ninja.pdf_generator') == 'phantom') {
|
||||||
|
return (new Phantom)->convertHtmlToPdf($maker->getCompiledHTML(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(config('ninja.invoiceninja_hosted_pdf_generation') || config('ninja.pdf_generator') == 'hosted_ninja'){
|
||||||
|
$pdf = (new NinjaPdf())->build($maker->getCompiledHTML(true));
|
||||||
|
|
||||||
|
$numbered_pdf = $this->pageNumbering($pdf, auth()->user()->company());
|
||||||
|
|
||||||
|
if($numbered_pdf)
|
||||||
|
$pdf = $numbered_pdf;
|
||||||
|
|
||||||
|
return $pdf;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//else
|
||||||
|
$file_path = PreviewPdf::dispatchNow($maker->getCompiledHTML(true), auth()->user()->company());
|
||||||
|
|
||||||
|
return response()->download($file_path, basename($file_path), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->blankEntity();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function live(PreviewPurchaseOrderRequest $request)
|
||||||
|
{
|
||||||
|
$company = auth()->user()->company();
|
||||||
|
|
||||||
|
MultiDB::setDb($company->db);
|
||||||
|
|
||||||
|
$repo = new PurchaseOrderRepository();
|
||||||
|
$entity_obj = PurchaseOrderFactory::create($company->id, auth()->user()->id);
|
||||||
|
$class = PurchaseOrder::class;
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
DB::connection(config('database.default'))->beginTransaction();
|
||||||
|
|
||||||
|
if($request->has('entity_id')){
|
||||||
|
|
||||||
|
$entity_obj = $class::on(config('database.default'))
|
||||||
|
->with('vendor.company')
|
||||||
|
->where('id', $this->decodePrimaryKey($request->input('entity_id')))
|
||||||
|
->where('company_id', $company->id)
|
||||||
|
->withTrashed()
|
||||||
|
->first();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$entity_obj = $repo->save($request->all(), $entity_obj);
|
||||||
|
|
||||||
|
if(!$request->has('entity_id'))
|
||||||
|
$entity_obj->service()->fillDefaults()->save();
|
||||||
|
|
||||||
|
App::forgetInstance('translator');
|
||||||
|
$t = app('translator');
|
||||||
|
App::setLocale($entity_obj->company->locale());
|
||||||
|
$t->replace(Ninja::transformTranslations($entity_obj->company->settings));
|
||||||
|
|
||||||
|
$html = new VendorHtmlEngine($entity_obj->invitations()->first());
|
||||||
|
|
||||||
|
$design = \App\Models\Design::find($entity_obj->design_id);
|
||||||
|
|
||||||
|
/* Catch all in case migration doesn't pass back a valid design */
|
||||||
|
if(!$design)
|
||||||
|
$design = \App\Models\Design::find(2);
|
||||||
|
|
||||||
|
if ($design->is_custom) {
|
||||||
|
$options = [
|
||||||
|
'custom_partials' => json_decode(json_encode($design->design), true)
|
||||||
|
];
|
||||||
|
$template = new PdfMakerDesign(PdfDesignModel::CUSTOM, $options);
|
||||||
|
} else {
|
||||||
|
$template = new PdfMakerDesign(strtolower($design->name));
|
||||||
|
}
|
||||||
|
|
||||||
|
$variables = $html->generateLabelsAndValues();
|
||||||
|
|
||||||
|
$state = [
|
||||||
|
'template' => $template->elements([
|
||||||
|
'client' => null,
|
||||||
|
'vendor' => $entity_obj->vendor,
|
||||||
|
'entity' => $entity_obj,
|
||||||
|
'pdf_variables' => (array) $entity_obj->company->settings->pdf_variables,
|
||||||
|
'variables' => $html->generateLabelsAndValues(),
|
||||||
|
'$product' => $design->design->product,
|
||||||
|
]),
|
||||||
|
'variables' => $html->generateLabelsAndValues(),
|
||||||
|
'process_markdown' => $entity_obj->company->markdown_enabled,
|
||||||
|
];
|
||||||
|
|
||||||
|
$maker = new PdfMaker($state);
|
||||||
|
|
||||||
|
$maker
|
||||||
|
->design($template)
|
||||||
|
->build();
|
||||||
|
|
||||||
|
DB::connection(config('database.default'))->rollBack();
|
||||||
|
|
||||||
|
if (request()->query('html') == 'true') {
|
||||||
|
return $maker->getCompiledHTML();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
catch(\Exception $e){
|
||||||
|
|
||||||
|
DB::connection(config('database.default'))->rollBack();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//if phantom js...... inject here..
|
||||||
|
if (config('ninja.phantomjs_pdf_generation') || config('ninja.pdf_generator') == 'phantom') {
|
||||||
|
return (new Phantom)->convertHtmlToPdf($maker->getCompiledHTML(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(config('ninja.invoiceninja_hosted_pdf_generation') || config('ninja.pdf_generator') == 'hosted_ninja'){
|
||||||
|
$pdf = (new NinjaPdf())->build($maker->getCompiledHTML(true));
|
||||||
|
|
||||||
|
$numbered_pdf = $this->pageNumbering($pdf, auth()->user()->company());
|
||||||
|
|
||||||
|
if($numbered_pdf)
|
||||||
|
$pdf = $numbered_pdf;
|
||||||
|
|
||||||
|
return $pdf;
|
||||||
|
}
|
||||||
|
|
||||||
|
$file_path = PreviewPdf::dispatchNow($maker->getCompiledHTML(true), $company);
|
||||||
|
|
||||||
|
|
||||||
|
if(Ninja::isHosted())
|
||||||
|
{
|
||||||
|
LightLogs::create(new LivePreview())
|
||||||
|
->increment()
|
||||||
|
->queue();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$response = Response::make($file_path, 200);
|
||||||
|
$response->header('Content-Type', 'application/pdf');
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function blankEntity()
|
||||||
|
{
|
||||||
|
App::forgetInstance('translator');
|
||||||
|
$t = app('translator');
|
||||||
|
$t->replace(Ninja::transformTranslations(auth()->user()->company()->settings));
|
||||||
|
|
||||||
|
$invitation = PurchaseOrderInvitation::where('company_id', auth()->user()->company()->id)->orderBy('id', 'desc')->first();
|
||||||
|
|
||||||
|
/* If we don't have a valid invitation in the system - create a mock using transactions */
|
||||||
|
if(!$invitation)
|
||||||
|
return $this->mockEntity();
|
||||||
|
|
||||||
|
$design_object = json_decode(json_encode(request()->input('design')));
|
||||||
|
|
||||||
|
if (! is_object($design_object)) {
|
||||||
|
return response()->json(['message' => 'Invalid custom design object'], 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$html = new VendorHtmlEngine($invitation);
|
||||||
|
|
||||||
|
$design = new Design(Design::CUSTOM, ['custom_partials' => request()->design['design']]);
|
||||||
|
|
||||||
|
$state = [
|
||||||
|
'template' => $design->elements([
|
||||||
|
'client' => null,
|
||||||
|
'vendor' => $invitation->purchase_order->vendor,
|
||||||
|
'entity' => $invitation->purchase_order,
|
||||||
|
'pdf_variables' => (array) $invitation->company->settings->pdf_variables,
|
||||||
|
'products' => request()->design['design']['product'],
|
||||||
|
]),
|
||||||
|
'variables' => $html->generateLabelsAndValues(),
|
||||||
|
'process_markdown' => $invitation->company->markdown_enabled,
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
$maker = new PdfMaker($state);
|
||||||
|
|
||||||
|
$maker
|
||||||
|
->design($design)
|
||||||
|
->build();
|
||||||
|
|
||||||
|
if (request()->query('html') == 'true') {
|
||||||
|
return $maker->getCompiledHTML();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config('ninja.phantomjs_pdf_generation') || config('ninja.pdf_generator') == 'phantom') {
|
||||||
|
return (new Phantom)->convertHtmlToPdf($maker->getCompiledHTML(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(config('ninja.invoiceninja_hosted_pdf_generation') || config('ninja.pdf_generator') == 'hosted_ninja'){
|
||||||
|
$pdf = (new NinjaPdf())->build($maker->getCompiledHTML(true));
|
||||||
|
|
||||||
|
$numbered_pdf = $this->pageNumbering($pdf, auth()->user()->company());
|
||||||
|
|
||||||
|
if($numbered_pdf)
|
||||||
|
$pdf = $numbered_pdf;
|
||||||
|
|
||||||
|
return $pdf;
|
||||||
|
}
|
||||||
|
|
||||||
|
$file_path = PreviewPdf::dispatchNow($maker->getCompiledHTML(true), auth()->user()->company());
|
||||||
|
|
||||||
|
$response = Response::make($file_path, 200);
|
||||||
|
$response->header('Content-Type', 'application/pdf');
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function mockEntity()
|
||||||
|
{
|
||||||
|
|
||||||
|
DB::connection(auth()->user()->company()->db)->beginTransaction();
|
||||||
|
|
||||||
|
$vendor = Vendor::factory()->create([
|
||||||
|
'user_id' => auth()->user()->id,
|
||||||
|
'company_id' => auth()->user()->company()->id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$contact = VendorContact::factory()->create([
|
||||||
|
'user_id' => auth()->user()->id,
|
||||||
|
'company_id' => auth()->user()->company()->id,
|
||||||
|
'vendor_id' => $vendor->id,
|
||||||
|
'is_primary' => 1,
|
||||||
|
'send_email' => true,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$purchase_order = PurchaseOrder::factory()->create([
|
||||||
|
'user_id' => auth()->user()->id,
|
||||||
|
'company_id' => auth()->user()->company()->id,
|
||||||
|
'vendor_id' => $vendor->id,
|
||||||
|
'terms' => 'Sample Terms',
|
||||||
|
'footer' => 'Sample Footer',
|
||||||
|
'public_notes' => 'Sample Public Notes',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$invitation = PurchaseOrderInvitation::factory()->create([
|
||||||
|
'user_id' => auth()->user()->id,
|
||||||
|
'company_id' => auth()->user()->company()->id,
|
||||||
|
'purchase_order_id' => $purchase_order->id,
|
||||||
|
'vendor_contact_id' => $contact->id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$purchase_order->setRelation('invitations', $invitation);
|
||||||
|
$purchase_order->setRelation('vendor', $vendor);
|
||||||
|
$purchase_order->setRelation('company', auth()->user()->company());
|
||||||
|
$purchase_order->load('vendor.company');
|
||||||
|
|
||||||
|
$design_object = json_decode(json_encode(request()->input('design')));
|
||||||
|
|
||||||
|
if (! is_object($design_object)) {
|
||||||
|
return response()->json(['message' => 'Invalid custom design object'], 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$html = new VendorHtmlEngine($purchase_order->invitations()->first());
|
||||||
|
|
||||||
|
$design = new Design(Design::CUSTOM, ['custom_partials' => request()->design['design']]);
|
||||||
|
|
||||||
|
$state = [
|
||||||
|
'template' => $design->elements([
|
||||||
|
'client' => null,
|
||||||
|
'vendor' => $purchase_order->vendor,
|
||||||
|
'entity' => $purchase_order,
|
||||||
|
'pdf_variables' => (array) $purchase_order->company->settings->pdf_variables,
|
||||||
|
'products' => request()->design['design']['product'],
|
||||||
|
]),
|
||||||
|
'variables' => $html->generateLabelsAndValues(),
|
||||||
|
'process_markdown' => $purchase_order->company->markdown_enabled,
|
||||||
|
];
|
||||||
|
|
||||||
|
$maker = new PdfMaker($state);
|
||||||
|
|
||||||
|
$maker
|
||||||
|
->design($design)
|
||||||
|
->build();
|
||||||
|
|
||||||
|
DB::connection(auth()->user()->company()->db)->rollBack();
|
||||||
|
|
||||||
|
if (request()->query('html') == 'true') {
|
||||||
|
return $maker->getCompiledHTML();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config('ninja.phantomjs_pdf_generation') || config('ninja.pdf_generator') == 'phantom') {
|
||||||
|
return (new Phantom)->convertHtmlToPdf($maker->getCompiledHTML(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(config('ninja.invoiceninja_hosted_pdf_generation') || config('ninja.pdf_generator') == 'hosted_ninja'){
|
||||||
|
$pdf = (new NinjaPdf())->build($maker->getCompiledHTML(true));
|
||||||
|
|
||||||
|
$numbered_pdf = $this->pageNumbering($pdf, auth()->user()->company());
|
||||||
|
|
||||||
|
if($numbered_pdf)
|
||||||
|
$pdf = $numbered_pdf;
|
||||||
|
|
||||||
|
return $pdf;
|
||||||
|
}
|
||||||
|
|
||||||
|
$file_path = PreviewPdf::dispatchNow($maker->getCompiledHTML(true), auth()->user()->company());
|
||||||
|
|
||||||
|
$response = Response::make($file_path, 200);
|
||||||
|
$response->header('Content-Type', 'application/pdf');
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
}
|
@ -17,11 +17,13 @@ use App\Events\Misc\InvitationWasViewed;
|
|||||||
use App\Events\Quote\QuoteWasViewed;
|
use App\Events\Quote\QuoteWasViewed;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Jobs\Entity\CreateRawPdf;
|
use App\Jobs\Entity\CreateRawPdf;
|
||||||
|
use App\Jobs\Vendor\CreatePurchaseOrderPdf;
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
use App\Models\ClientContact;
|
use App\Models\ClientContact;
|
||||||
use App\Models\CreditInvitation;
|
use App\Models\CreditInvitation;
|
||||||
use App\Models\InvoiceInvitation;
|
use App\Models\InvoiceInvitation;
|
||||||
use App\Models\Payment;
|
use App\Models\Payment;
|
||||||
|
use App\Models\PurchaseOrder;
|
||||||
use App\Models\PurchaseOrderInvitation;
|
use App\Models\PurchaseOrderInvitation;
|
||||||
use App\Models\QuoteInvitation;
|
use App\Models\QuoteInvitation;
|
||||||
use App\Services\ClientPortal\InstantPayment;
|
use App\Services\ClientPortal\InstantPayment;
|
||||||
@ -95,50 +97,32 @@ class InvitationController extends Controller
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function download(string $invitation_key)
|
||||||
|
{
|
||||||
|
$invitation = PurchaseOrderInvitation::withTrashed()
|
||||||
|
->where('key', $invitation_key)
|
||||||
|
->with('contact.vendor')
|
||||||
|
->firstOrFail();
|
||||||
|
|
||||||
|
if(!$invitation)
|
||||||
|
return response()->json(["message" => "no record found"], 400);
|
||||||
|
|
||||||
// public function routerForDownload(string $entity, string $invitation_key)
|
$file_name = $invitation->purchase_order->numberFormatter().'.pdf';
|
||||||
// {
|
|
||||||
|
|
||||||
// set_time_limit(45);
|
|
||||||
|
|
||||||
// if(Ninja::isHosted())
|
|
||||||
// return $this->returnRawPdf($entity, $invitation_key);
|
|
||||||
|
|
||||||
// return redirect('client/'.$entity.'/'.$invitation_key.'/download_pdf');
|
|
||||||
// }
|
|
||||||
|
|
||||||
// private function returnRawPdf(string $entity, string $invitation_key)
|
|
||||||
// {
|
|
||||||
|
|
||||||
// if(!in_array($entity, ['invoice', 'credit', 'quote', 'recurring_invoice']))
|
|
||||||
// return response()->json(['message' => 'Invalid resource request']);
|
|
||||||
|
|
||||||
// $key = $entity.'_id';
|
|
||||||
|
|
||||||
// $entity_obj = 'App\Models\\'.ucfirst(Str::camel($entity)).'Invitation';
|
|
||||||
|
|
||||||
// $invitation = $entity_obj::where('key', $invitation_key)
|
|
||||||
// ->with('contact.client')
|
|
||||||
// ->firstOrFail();
|
|
||||||
|
|
||||||
// if(!$invitation)
|
|
||||||
// return response()->json(["message" => "no record found"], 400);
|
|
||||||
|
|
||||||
// $file_name = $invitation->purchase_order->numberFormatter().'.pdf';
|
|
||||||
|
|
||||||
// $file = CreateRawPdf::dispatchNow($invitation, $invitation->company->db);
|
// $file = CreateRawPdf::dispatchNow($invitation, $invitation->company->db);
|
||||||
|
|
||||||
// $headers = ['Content-Type' => 'application/pdf'];
|
$file = (new CreatePurchaseOrderPdf($invitation))->rawPdf();
|
||||||
|
|
||||||
// if(request()->input('inline') == 'true')
|
$headers = ['Content-Type' => 'application/pdf'];
|
||||||
// $headers = array_merge($headers, ['Content-Disposition' => 'inline']);
|
|
||||||
|
|
||||||
// return response()->streamDownload(function () use($file) {
|
if(request()->input('inline') == 'true')
|
||||||
// echo $file;
|
$headers = array_merge($headers, ['Content-Disposition' => 'inline']);
|
||||||
// }, $file_name, $headers);
|
|
||||||
|
return response()->streamDownload(function () use($file) {
|
||||||
|
echo $file;
|
||||||
|
}, $file_name, $headers);
|
||||||
|
}
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
62
app/Http/Requests/Preview/PreviewPurchaseOrderRequest.php
Normal file
62
app/Http/Requests/Preview/PreviewPurchaseOrderRequest.php
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Preview;
|
||||||
|
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
use App\Http\ValidationRules\Project\ValidProjectForClient;
|
||||||
|
use App\Models\Credit;
|
||||||
|
use App\Models\Invoice;
|
||||||
|
use App\Models\PurchaseOrder;
|
||||||
|
use App\Models\Quote;
|
||||||
|
use App\Models\RecurringInvoice;
|
||||||
|
use App\Utils\Traits\CleanLineItems;
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
|
class PreviewPurchaseOrderRequest extends Request
|
||||||
|
{
|
||||||
|
use MakesHash;
|
||||||
|
use CleanLineItems;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize() : bool
|
||||||
|
{
|
||||||
|
return auth()->user()->can('create', PurchaseOrder::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
$rules = [];
|
||||||
|
|
||||||
|
$rules['number'] = ['nullable'];
|
||||||
|
|
||||||
|
return $rules;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function prepareForValidation()
|
||||||
|
{
|
||||||
|
$input = $this->all();
|
||||||
|
|
||||||
|
$input = $this->decodePrimaryKeys($input);
|
||||||
|
|
||||||
|
$input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : [];
|
||||||
|
$input['amount'] = 0;
|
||||||
|
$input['balance'] = 0;
|
||||||
|
$input['number'] = ctrans('texts.live_preview') . " #". rand(0,1000);
|
||||||
|
|
||||||
|
$this->replace($input);
|
||||||
|
}
|
||||||
|
}
|
@ -1423,21 +1423,21 @@ class CompanyImport implements ShouldQueue
|
|||||||
$new_obj->company_id = $this->company->id;
|
$new_obj->company_id = $this->company->id;
|
||||||
$new_obj->fill($obj_array);
|
$new_obj->fill($obj_array);
|
||||||
$new_obj->save(['timestamps' => false]);
|
$new_obj->save(['timestamps' => false]);
|
||||||
$new_obj->number = $this->getNextInvoiceNumber($client = Client::find($obj_array['client_id']),$new_obj);
|
$new_obj->number = $this->getNextInvoiceNumber($client = Client::withTrashed()->find($obj_array['client_id']),$new_obj);
|
||||||
}
|
}
|
||||||
elseif($class == 'App\Models\Payment' && is_null($obj->{$match_key})){
|
elseif($class == 'App\Models\Payment' && is_null($obj->{$match_key})){
|
||||||
$new_obj = new Payment();
|
$new_obj = new Payment();
|
||||||
$new_obj->company_id = $this->company->id;
|
$new_obj->company_id = $this->company->id;
|
||||||
$new_obj->fill($obj_array);
|
$new_obj->fill($obj_array);
|
||||||
$new_obj->save(['timestamps' => false]);
|
$new_obj->save(['timestamps' => false]);
|
||||||
$new_obj->number = $this->getNextPaymentNumber($client = Client::find($obj_array['client_id']), $new_obj);
|
$new_obj->number = $this->getNextPaymentNumber($client = Client::withTrashed()->find($obj_array['client_id']), $new_obj);
|
||||||
}
|
}
|
||||||
elseif($class == 'App\Models\Quote' && is_null($obj->{$match_key})){
|
elseif($class == 'App\Models\Quote' && is_null($obj->{$match_key})){
|
||||||
$new_obj = new Quote();
|
$new_obj = new Quote();
|
||||||
$new_obj->company_id = $this->company->id;
|
$new_obj->company_id = $this->company->id;
|
||||||
$new_obj->fill($obj_array);
|
$new_obj->fill($obj_array);
|
||||||
$new_obj->save(['timestamps' => false]);
|
$new_obj->save(['timestamps' => false]);
|
||||||
$new_obj->number = $this->getNextQuoteNumber($client = Client::find($obj_array['client_id']), $new_obj);
|
$new_obj->number = $this->getNextQuoteNumber($client = Client::withTrashed()->find($obj_array['client_id']), $new_obj);
|
||||||
}
|
}
|
||||||
elseif($class == 'App\Models\ClientContact'){
|
elseif($class == 'App\Models\ClientContact'){
|
||||||
$new_obj = new ClientContact();
|
$new_obj = new ClientContact();
|
||||||
|
@ -308,8 +308,9 @@ class NinjaMailerJob implements ShouldQueue
|
|||||||
|
|
||||||
private function preFlightChecksFail()
|
private function preFlightChecksFail()
|
||||||
{
|
{
|
||||||
|
|
||||||
/* If we are migrating data we don't want to fire any emails */
|
/* If we are migrating data we don't want to fire any emails */
|
||||||
if ($this->nmo->company->is_disabled && !$this->override)
|
if($this->nmo->company->is_disabled && !$this->override)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
/* On the hosted platform we set default contacts a @example.com email address - we shouldn't send emails to these types of addresses */
|
/* On the hosted platform we set default contacts a @example.com email address - we shouldn't send emails to these types of addresses */
|
||||||
@ -324,6 +325,9 @@ class NinjaMailerJob implements ShouldQueue
|
|||||||
if(Ninja::isHosted() && $this->company->account && $this->company->account->emailQuotaExceeded())
|
if(Ninja::isHosted() && $this->company->account && $this->company->account->emailQuotaExceeded())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
if(Ninja::isHosted() && $this->company->account && $this->nmo->company->account->is_flagged)
|
||||||
|
return true;
|
||||||
|
|
||||||
/* Ensure the user has a valid email address */
|
/* Ensure the user has a valid email address */
|
||||||
if(!str_contains($this->nmo->to_user->email, "@"))
|
if(!str_contains($this->nmo->to_user->email, "@"))
|
||||||
return true;
|
return true;
|
||||||
|
53
app/Jobs/Vendor/CreatePurchaseOrderPdf.php
vendored
53
app/Jobs/Vendor/CreatePurchaseOrderPdf.php
vendored
@ -65,6 +65,10 @@ class CreatePurchaseOrderPdf implements ShouldQueue
|
|||||||
|
|
||||||
public $vendor;
|
public $vendor;
|
||||||
|
|
||||||
|
private string $path = '';
|
||||||
|
|
||||||
|
private string $file_path = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new job instance.
|
* Create a new job instance.
|
||||||
*
|
*
|
||||||
@ -88,6 +92,32 @@ class CreatePurchaseOrderPdf implements ShouldQueue
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function handle()
|
public function handle()
|
||||||
|
{
|
||||||
|
|
||||||
|
$pdf = $this->rawPdf();
|
||||||
|
|
||||||
|
if ($pdf) {
|
||||||
|
|
||||||
|
try{
|
||||||
|
|
||||||
|
if(!Storage::disk($this->disk)->exists($this->path))
|
||||||
|
Storage::disk($this->disk)->makeDirectory($this->path, 0775);
|
||||||
|
|
||||||
|
Storage::disk($this->disk)->put($this->file_path, $pdf, 'public');
|
||||||
|
|
||||||
|
}
|
||||||
|
catch(\Exception $e)
|
||||||
|
{
|
||||||
|
|
||||||
|
throw new FilePermissionsFailure($e->getMessage());
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->file_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rawPdf()
|
||||||
{
|
{
|
||||||
|
|
||||||
MultiDB::setDb($this->company->db);
|
MultiDB::setDb($this->company->db);
|
||||||
@ -109,10 +139,10 @@ class CreatePurchaseOrderPdf implements ShouldQueue
|
|||||||
|
|
||||||
$entity_design_id = '';
|
$entity_design_id = '';
|
||||||
|
|
||||||
$path = $this->vendor->purchase_order_filepath($this->invitation);
|
$this->path = $this->vendor->purchase_order_filepath($this->invitation);
|
||||||
$entity_design_id = 'purchase_order_design_id';
|
$entity_design_id = 'purchase_order_design_id';
|
||||||
|
|
||||||
$file_path = $path.$this->entity->numberFormatter().'.pdf';
|
$this->file_path = $this->path.$this->entity->numberFormatter().'.pdf';
|
||||||
|
|
||||||
$entity_design_id = $this->entity->design_id ? $this->entity->design_id : $this->decodePrimaryKey('Wpmbk5ezJn');
|
$entity_design_id = $this->entity->design_id ? $this->entity->design_id : $this->decodePrimaryKey('Wpmbk5ezJn');
|
||||||
|
|
||||||
@ -191,25 +221,8 @@ class CreatePurchaseOrderPdf implements ShouldQueue
|
|||||||
info($maker->getCompiledHTML());
|
info($maker->getCompiledHTML());
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($pdf) {
|
return $pdf;
|
||||||
|
|
||||||
try{
|
|
||||||
|
|
||||||
if(!Storage::disk($this->disk)->exists($path))
|
|
||||||
Storage::disk($this->disk)->makeDirectory($path, 0775);
|
|
||||||
|
|
||||||
Storage::disk($this->disk)->put($file_path, $pdf, 'public');
|
|
||||||
|
|
||||||
}
|
|
||||||
catch(\Exception $e)
|
|
||||||
{
|
|
||||||
|
|
||||||
throw new FilePermissionsFailure($e->getMessage());
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $file_path;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function failed($e)
|
public function failed($e)
|
||||||
|
@ -33,7 +33,7 @@ class Account extends BaseModel
|
|||||||
use PresentableTrait;
|
use PresentableTrait;
|
||||||
use MakesHash;
|
use MakesHash;
|
||||||
|
|
||||||
private $free_plan_email_quota = 250;
|
private $free_plan_email_quota = 100;
|
||||||
|
|
||||||
private $paid_plan_email_quota = 500;
|
private $paid_plan_email_quota = 500;
|
||||||
/**
|
/**
|
||||||
@ -373,10 +373,15 @@ class Account extends BaseModel
|
|||||||
|
|
||||||
public function getDailyEmailLimit()
|
public function getDailyEmailLimit()
|
||||||
{
|
{
|
||||||
|
if($this->is_flagged)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if(Carbon::createFromTimestamp($this->created_at)->diffInWeeks() == 0)
|
if(Carbon::createFromTimestamp($this->created_at)->diffInWeeks() == 0)
|
||||||
return 20;
|
return 20;
|
||||||
|
|
||||||
|
if(Carbon::createFromTimestamp($this->created_at)->diffInWeeks() <= 2 && !$this->payment_id)
|
||||||
|
return 20;
|
||||||
|
|
||||||
if($this->isPaid()){
|
if($this->isPaid()){
|
||||||
$limit = $this->paid_plan_email_quota;
|
$limit = $this->paid_plan_email_quota;
|
||||||
$limit += Carbon::createFromTimestamp($this->created_at)->diffInMonths() * 100;
|
$limit += Carbon::createFromTimestamp($this->created_at)->diffInMonths() * 100;
|
||||||
|
@ -126,6 +126,26 @@ class CompanyPresenter extends EntityPresenter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function address1()
|
||||||
|
{
|
||||||
|
return $this->entity->settings->address1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function address2()
|
||||||
|
{
|
||||||
|
return $this->entity->settings->address2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function qr_iban()
|
||||||
|
{
|
||||||
|
return $this->entity->getSetting('qr_iban');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function besr_id()
|
||||||
|
{
|
||||||
|
return $this->entity->getSetting('besr_id');
|
||||||
|
}
|
||||||
|
|
||||||
public function getSpcQrCode($client_currency, $invoice_number, $balance_due_raw, $user_iban)
|
public function getSpcQrCode($client_currency, $invoice_number, $balance_due_raw, $user_iban)
|
||||||
{
|
{
|
||||||
$settings = $this->entity->settings;
|
$settings = $this->entity->settings;
|
||||||
|
@ -16,8 +16,12 @@ use App\Models\Client;
|
|||||||
use App\Models\ClientContact;
|
use App\Models\ClientContact;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
use App\Models\InvoiceInvitation;
|
use App\Models\InvoiceInvitation;
|
||||||
|
use App\Models\PurchaseOrder;
|
||||||
|
use App\Models\PurchaseOrderInvitation;
|
||||||
use App\Models\Quote;
|
use App\Models\Quote;
|
||||||
use App\Models\QuoteInvitation;
|
use App\Models\QuoteInvitation;
|
||||||
|
use App\Models\Vendor;
|
||||||
|
use App\Models\VendorContact;
|
||||||
use App\Services\PdfMaker\Designs\Utilities\DesignHelpers;
|
use App\Services\PdfMaker\Designs\Utilities\DesignHelpers;
|
||||||
use App\Utils\Ninja;
|
use App\Utils\Ninja;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
@ -26,6 +30,7 @@ use App\Utils\Traits\MakesTemplateData;
|
|||||||
use DB;
|
use DB;
|
||||||
use Illuminate\Support\Facades\App;
|
use Illuminate\Support\Facades\App;
|
||||||
use Illuminate\Support\Facades\Lang;
|
use Illuminate\Support\Facades\Lang;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
use League\CommonMark\CommonMarkConverter;
|
use League\CommonMark\CommonMarkConverter;
|
||||||
use TijsVerkoyen\CssToInlineStyles\CssToInlineStyles;
|
use TijsVerkoyen\CssToInlineStyles\CssToInlineStyles;
|
||||||
|
|
||||||
@ -88,7 +93,7 @@ class TemplateEngine
|
|||||||
private function setEntity()
|
private function setEntity()
|
||||||
{
|
{
|
||||||
if (strlen($this->entity) > 1 && strlen($this->entity_id) > 1) {
|
if (strlen($this->entity) > 1 && strlen($this->entity_id) > 1) {
|
||||||
$class = 'App\Models\\'.ucfirst($this->entity);
|
$class = 'App\Models\\'.ucfirst(Str::camel($this->entity));
|
||||||
$this->entity_obj = $class::withTrashed()->where('id', $this->decodePrimaryKey($this->entity_id))->company()->first();
|
$this->entity_obj = $class::withTrashed()->where('id', $this->decodePrimaryKey($this->entity_id))->company()->first();
|
||||||
} else {
|
} else {
|
||||||
$this->mockEntity();
|
$this->mockEntity();
|
||||||
@ -99,7 +104,11 @@ class TemplateEngine
|
|||||||
|
|
||||||
private function setSettingsObject()
|
private function setSettingsObject()
|
||||||
{
|
{
|
||||||
if ($this->entity_obj) {
|
if($this->entity == 'purchase_order'){
|
||||||
|
$this->settings_entity = auth()->user()->company();
|
||||||
|
$this->settings = $this->settings_entity->settings;
|
||||||
|
}
|
||||||
|
elseif ($this->entity_obj) {
|
||||||
$this->settings_entity = $this->entity_obj->client;
|
$this->settings_entity = $this->entity_obj->client;
|
||||||
$this->settings = $this->settings_entity->getMergedSettings();
|
$this->settings = $this->settings_entity->getMergedSettings();
|
||||||
} else {
|
} else {
|
||||||
@ -143,7 +152,10 @@ class TemplateEngine
|
|||||||
$this->raw_body = $this->body;
|
$this->raw_body = $this->body;
|
||||||
$this->raw_subject = $this->subject;
|
$this->raw_subject = $this->subject;
|
||||||
|
|
||||||
if ($this->entity_obj) {
|
if($this->entity == 'purchase_order'){
|
||||||
|
$this->fakerValues();
|
||||||
|
}
|
||||||
|
elseif ($this->entity_obj) {
|
||||||
$this->entityValues($this->entity_obj->client->primary_contact()->first());
|
$this->entityValues($this->entity_obj->client->primary_contact()->first());
|
||||||
} else {
|
} else {
|
||||||
$this->fakerValues();
|
$this->fakerValues();
|
||||||
@ -198,7 +210,17 @@ class TemplateEngine
|
|||||||
$data['footer'] = '';
|
$data['footer'] = '';
|
||||||
$data['logo'] = auth()->user()->company()->present()->logo();
|
$data['logo'] = auth()->user()->company()->present()->logo();
|
||||||
|
|
||||||
|
if($this->entity_obj->client)
|
||||||
$data = array_merge($data, Helpers::sharedEmailVariables($this->entity_obj->client));
|
$data = array_merge($data, Helpers::sharedEmailVariables($this->entity_obj->client));
|
||||||
|
else{
|
||||||
|
|
||||||
|
$data['signature'] = $this->settings->email_signature;
|
||||||
|
$data['settings'] = $this->settings;
|
||||||
|
$data['whitelabel'] = $this->entity_obj ? $this->entity_obj->company->account->isPaid() : true;
|
||||||
|
$data['company'] = $this->entity_obj ? $this->entity_obj->company : '';
|
||||||
|
$data['settings'] = $this->settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if ($email_style == 'custom') {
|
if ($email_style == 'custom') {
|
||||||
$wrapper = $this->settings_entity->getSetting('email_style_custom');
|
$wrapper = $this->settings_entity->getSetting('email_style_custom');
|
||||||
@ -243,6 +265,8 @@ class TemplateEngine
|
|||||||
{
|
{
|
||||||
DB::connection(config('database.default'))->beginTransaction();
|
DB::connection(config('database.default'))->beginTransaction();
|
||||||
|
|
||||||
|
$vendor = false;
|
||||||
|
|
||||||
$client = Client::factory()->create([
|
$client = Client::factory()->create([
|
||||||
'user_id' => auth()->user()->id,
|
'user_id' => auth()->user()->id,
|
||||||
'company_id' => auth()->user()->company()->id,
|
'company_id' => auth()->user()->company()->id,
|
||||||
@ -289,6 +313,53 @@ class TemplateEngine
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if($this->entity == 'purchase_order')
|
||||||
|
{
|
||||||
|
|
||||||
|
$vendor = Vendor::factory()->create([
|
||||||
|
'user_id' => auth()->user()->id,
|
||||||
|
'company_id' => auth()->user()->company()->id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$contact = VendorContact::factory()->create([
|
||||||
|
'user_id' => auth()->user()->id,
|
||||||
|
'company_id' => auth()->user()->company()->id,
|
||||||
|
'vendor_id' => $vendor->id,
|
||||||
|
'is_primary' => 1,
|
||||||
|
'send_email' => true,
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
$this->entity_obj = PurchaseOrder::factory()->create([
|
||||||
|
'user_id' => auth()->user()->id,
|
||||||
|
'company_id' => auth()->user()->company()->id,
|
||||||
|
'vendor_id' => $vendor->id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$invitation = PurchaseOrderInvitation::factory()->create([
|
||||||
|
'user_id' => auth()->user()->id,
|
||||||
|
'company_id' => auth()->user()->company()->id,
|
||||||
|
'purchase_order_id' => $this->entity_obj->id,
|
||||||
|
'vendor_contact_id' => $contact->id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if($vendor)
|
||||||
|
{
|
||||||
|
|
||||||
|
$this->entity_obj->setRelation('invitations', $invitation);
|
||||||
|
$this->entity_obj->setRelation('vendor', $vendor);
|
||||||
|
$this->entity_obj->setRelation('company', auth()->user()->company());
|
||||||
|
$this->entity_obj->load('vendor');
|
||||||
|
$vendor->setRelation('company', auth()->user()->company());
|
||||||
|
$vendor->load('company');
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
$this->entity_obj->setRelation('invitations', $invitation);
|
$this->entity_obj->setRelation('invitations', $invitation);
|
||||||
$this->entity_obj->setRelation('client', $client);
|
$this->entity_obj->setRelation('client', $client);
|
||||||
$this->entity_obj->setRelation('company', auth()->user()->company());
|
$this->entity_obj->setRelation('company', auth()->user()->company());
|
||||||
@ -296,6 +367,7 @@ class TemplateEngine
|
|||||||
$client->setRelation('company', auth()->user()->company());
|
$client->setRelation('company', auth()->user()->company());
|
||||||
$client->load('company');
|
$client->load('company');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private function tearDown()
|
private function tearDown()
|
||||||
{
|
{
|
||||||
|
@ -120,6 +120,9 @@ trait CompanySettingsSaver
|
|||||||
elseif (substr($key, -3) == '_id' || substr($key, -14) == 'number_counter') {
|
elseif (substr($key, -3) == '_id' || substr($key, -14) == 'number_counter') {
|
||||||
$value = 'integer';
|
$value = 'integer';
|
||||||
|
|
||||||
|
if($key == 'besr_id')
|
||||||
|
$value = 'string';
|
||||||
|
|
||||||
if (! property_exists($settings, $key)) {
|
if (! property_exists($settings, $key)) {
|
||||||
continue;
|
continue;
|
||||||
} elseif (! $this->checkAttribute($value, $settings->{$key})) {
|
} elseif (! $this->checkAttribute($value, $settings->{$key})) {
|
||||||
@ -187,6 +190,9 @@ trait CompanySettingsSaver
|
|||||||
if($key == 'gmail_sending_user_id')
|
if($key == 'gmail_sending_user_id')
|
||||||
$value = 'string';
|
$value = 'string';
|
||||||
|
|
||||||
|
if($key == 'besr_id')
|
||||||
|
$value = 'string';
|
||||||
|
|
||||||
if (! property_exists($settings, $key)) {
|
if (! property_exists($settings, $key)) {
|
||||||
continue;
|
continue;
|
||||||
} elseif ($this->checkAttribute($value, $settings->{$key})) {
|
} elseif ($this->checkAttribute($value, $settings->{$key})) {
|
||||||
|
@ -200,6 +200,36 @@ trait MakesTemplateData
|
|||||||
$data['$task.tax_name3'] = ['value' => 'CA Sales Tax', 'label' => ctrans('texts.tax')];
|
$data['$task.tax_name3'] = ['value' => 'CA Sales Tax', 'label' => ctrans('texts.tax')];
|
||||||
$data['$task.line_total'] = ['value' => '$100.00', 'label' => ctrans('texts.line_total')];
|
$data['$task.line_total'] = ['value' => '$100.00', 'label' => ctrans('texts.line_total')];
|
||||||
|
|
||||||
|
$data['$vendor_name'] = &$data['$client_name'];
|
||||||
|
$data['$vendor.name'] = &$data['$client_name'];
|
||||||
|
$data['$vendor'] = &$data['$client_name'];
|
||||||
|
|
||||||
|
$data['$vendor.address1'] = &$data['$address1'];
|
||||||
|
$data['$vendor.address2'] = &$data['$address2'];
|
||||||
|
$data['$vendor_address'] = ['value' => '5 Kalamazoo Way\n Jimbuckeroo\n USA 90210', 'label' => ctrans('texts.address')];
|
||||||
|
$data['$vendor.address'] = &$data['$vendor_address'];
|
||||||
|
$data['$vendor.postal_code'] = ['value' => '90210', 'label' => ctrans('texts.postal_code')];
|
||||||
|
$data['$vendor.public_notes'] = $data['$invoice.public_notes'];
|
||||||
|
$data['$vendor.city'] = &$data['$company.city'];
|
||||||
|
$data['$vendor.state'] = &$data['$company.state'];
|
||||||
|
$data['$vendor.id_number'] = &$data['$id_number'];
|
||||||
|
$data['$vendor.vat_number'] = &$data['$vat_number'];
|
||||||
|
$data['$vendor.website'] = &$data['$website'];
|
||||||
|
$data['$vendor.phone'] = &$data['$phone'];
|
||||||
|
$data['$vendor.city_state_postal'] = &$data['$city_state_postal'];
|
||||||
|
$data['$vendor.postal_city_state'] = &$data['$postal_city_state'];
|
||||||
|
$data['$vendor.country'] = &$data['$country'];
|
||||||
|
$data['$vendor.email'] = &$data['$email'];
|
||||||
|
|
||||||
|
$data['$vendor.billing_address1'] = &$data['$vendor.address1'];
|
||||||
|
$data['$vendor.billing_address2'] = &$data['$vendor.address2'];
|
||||||
|
$data['$vendor.billing_city'] = &$data['$vendor.city'];
|
||||||
|
$data['$vendor.billing_state'] = &$data['$vendor.state'];
|
||||||
|
$data['$vendor.billing_postal_code'] = &$data['$vendor.postal_code'];
|
||||||
|
$data['$vendor.billing_country'] = &$data['$vendor.country'];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//$data['$paid_to_date'] = ;
|
//$data['$paid_to_date'] = ;
|
||||||
// $data['$your_invoice'] = ;
|
// $data['$your_invoice'] = ;
|
||||||
// $data['$quote'] = ;
|
// $data['$quote'] = ;
|
||||||
|
@ -55,7 +55,7 @@ trait SettingsSaver
|
|||||||
elseif (substr($key, -3) == '_id' || substr($key, -14) == 'number_counter' || ($key == 'payment_terms' && strlen($settings->{$key}) >= 1) || ($key == 'valid_until' && strlen($settings->{$key}) >= 1)) {
|
elseif (substr($key, -3) == '_id' || substr($key, -14) == 'number_counter' || ($key == 'payment_terms' && strlen($settings->{$key}) >= 1) || ($key == 'valid_until' && strlen($settings->{$key}) >= 1)) {
|
||||||
$value = 'integer';
|
$value = 'integer';
|
||||||
|
|
||||||
if($key == 'gmail_sending_user_id')
|
if($key == 'gmail_sending_user_id' || $key == 'besr_id')
|
||||||
$value = 'string';
|
$value = 'string';
|
||||||
|
|
||||||
if (! property_exists($settings, $key)) {
|
if (! property_exists($settings, $key)) {
|
||||||
|
@ -85,6 +85,7 @@
|
|||||||
"setasign/fpdi": "^2.3",
|
"setasign/fpdi": "^2.3",
|
||||||
"socialiteproviders/apple": "^5.2",
|
"socialiteproviders/apple": "^5.2",
|
||||||
"socialiteproviders/microsoft": "^4.1",
|
"socialiteproviders/microsoft": "^4.1",
|
||||||
|
"sprain/swiss-qr-bill": "^3.2",
|
||||||
"square/square": "13.0.0.20210721",
|
"square/square": "13.0.0.20210721",
|
||||||
"stripe/stripe-php": "^7.50",
|
"stripe/stripe-php": "^7.50",
|
||||||
"symfony/http-client": "^5.2",
|
"symfony/http-client": "^5.2",
|
||||||
|
1042
composer.lock
generated
1042
composer.lock
generated
File diff suppressed because it is too large
Load Diff
51
database/factories/PurchaseOrderFactory.php
Normal file
51
database/factories/PurchaseOrderFactory.php
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
namespace Database\Factories;
|
||||||
|
|
||||||
|
use App\Factory\InvoiceItemFactory;
|
||||||
|
use App\Models\Invoice;
|
||||||
|
use App\Models\PurchaseOrder;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
|
|
||||||
|
class PurchaseOrderFactory extends Factory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name of the factory's corresponding model.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $model = PurchaseOrder::class;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define the model's default state.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function definition()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'status_id' => Invoice::STATUS_SENT,
|
||||||
|
'number' => $this->faker->ean13(),
|
||||||
|
'discount' => $this->faker->numberBetween(1, 10),
|
||||||
|
'is_amount_discount' => (bool) random_int(0, 1),
|
||||||
|
'tax_name1' => 'GST',
|
||||||
|
'tax_rate1' => 10,
|
||||||
|
'tax_name2' => 'VAT',
|
||||||
|
'tax_rate2' => 17.5,
|
||||||
|
'is_deleted' => false,
|
||||||
|
'po_number' => $this->faker->text(10),
|
||||||
|
'date' => $this->faker->date(),
|
||||||
|
'due_date' => $this->faker->date(),
|
||||||
|
'line_items' => InvoiceItemFactory::generate(5),
|
||||||
|
'terms' => $this->faker->text(500),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
class AddFlagToAccountsTable extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('accounts', function (Blueprint $table) {
|
||||||
|
$table->boolean('is_flagged')->default(0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -129,6 +129,9 @@ Route::group(['middleware' => ['throttle:100,1', 'api_db', 'token_auth', 'locale
|
|||||||
Route::post('preview', 'PreviewController@show')->name('preview.show');
|
Route::post('preview', 'PreviewController@show')->name('preview.show');
|
||||||
Route::post('live_preview', 'PreviewController@live')->name('preview.live');
|
Route::post('live_preview', 'PreviewController@live')->name('preview.live');
|
||||||
|
|
||||||
|
Route::post('preview/purchase_order', 'PreviewPurchaseOrderController@show')->name('preview_purchase_order.show');
|
||||||
|
Route::post('live_preview/purchase_order', 'PreviewPurchaseOrderController@live')->name('preview_purchase_order.live');
|
||||||
|
|
||||||
Route::resource('products', 'ProductController'); // name = (products. index / create / show / update / destroy / edit
|
Route::resource('products', 'ProductController'); // name = (products. index / create / show / update / destroy / edit
|
||||||
Route::post('products/bulk', 'ProductController@bulk')->name('products.bulk');
|
Route::post('products/bulk', 'ProductController@bulk')->name('products.bulk');
|
||||||
Route::put('products/{product}/upload', 'ProductController@upload');
|
Route::put('products/{product}/upload', 'ProductController@upload');
|
||||||
|
@ -20,6 +20,8 @@ Route::get('vendors', [VendorContactLoginController::class, 'catch'])->name('ven
|
|||||||
Route::group(['middleware' => ['invite_db'], 'prefix' => 'vendor', 'as' => 'vendor.'], function () {
|
Route::group(['middleware' => ['invite_db'], 'prefix' => 'vendor', 'as' => 'vendor.'], function () {
|
||||||
/*Invitation catches*/
|
/*Invitation catches*/
|
||||||
Route::get('purchase_order/{invitation_key}', [InvitationController::class, 'purchaseOrder']);
|
Route::get('purchase_order/{invitation_key}', [InvitationController::class, 'purchaseOrder']);
|
||||||
|
Route::get('purchase_order/{invitation_key}/download', [InvitationController::class, 'download']);
|
||||||
|
|
||||||
// Route::get('purchase_order/{invitation_key}/download_pdf', 'PurchaseOrderController@downloadPdf')->name('recurring_invoice.download_invitation_key');
|
// Route::get('purchase_order/{invitation_key}/download_pdf', 'PurchaseOrderController@downloadPdf')->name('recurring_invoice.download_invitation_key');
|
||||||
// Route::get('purchase_order/{invitation_key}/download', 'ClientPortal\InvitationController@routerForDownload');
|
// Route::get('purchase_order/{invitation_key}/download', 'ClientPortal\InvitationController@routerForDownload');
|
||||||
|
|
||||||
@ -40,4 +42,7 @@ Route::group(['middleware' => ['auth:vendor', 'vendor_locale', 'domain_db'], 'pr
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Route::fallback('BaseController@notFoundVendor');
|
Route::fallback('BaseController@notFoundVendor');
|
@ -56,7 +56,7 @@ class CompanySettingsTest extends TestCase
|
|||||||
$response = $this->withHeaders([
|
$response = $this->withHeaders([
|
||||||
'X-API-SECRET' => config('ninja.api_secret'),
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
'X-API-Token' => $this->token,
|
'X-API-Token' => $this->token,
|
||||||
])->put('/api/v1/companies/'.$this->encodePrimaryKey($this->company->id), $this->company->toArray());
|
])->putJson('/api/v1/companies/'.$this->encodePrimaryKey($this->company->id), $this->company->toArray());
|
||||||
} catch (ValidationException $e) {
|
} catch (ValidationException $e) {
|
||||||
$message = json_decode($e->validator->getMessageBag(), 1);
|
$message = json_decode($e->validator->getMessageBag(), 1);
|
||||||
}
|
}
|
||||||
@ -78,11 +78,13 @@ class CompanySettingsTest extends TestCase
|
|||||||
|
|
||||||
$this->company->saveSettings($settings, $this->company);
|
$this->company->saveSettings($settings, $this->company);
|
||||||
|
|
||||||
|
$response = false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$response = $this->withHeaders([
|
$response = $this->withHeaders([
|
||||||
'X-API-SECRET' => config('ninja.api_secret'),
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
'X-API-Token' => $this->token,
|
'X-API-Token' => $this->token,
|
||||||
])->put('/api/v1/companies/'.$this->encodePrimaryKey($this->company->id), $this->company->toArray());
|
])->putJson('/api/v1/companies/'.$this->encodePrimaryKey($this->company->id), $this->company->toArray());
|
||||||
} catch (ValidationException $e) {
|
} catch (ValidationException $e) {
|
||||||
$message = json_decode($e->validator->getMessageBag(), 1);
|
$message = json_decode($e->validator->getMessageBag(), 1);
|
||||||
nlog($message);
|
nlog($message);
|
||||||
@ -109,7 +111,7 @@ class CompanySettingsTest extends TestCase
|
|||||||
$response = $this->withHeaders([
|
$response = $this->withHeaders([
|
||||||
'X-API-SECRET' => config('ninja.api_secret'),
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
'X-API-Token' => $this->token,
|
'X-API-Token' => $this->token,
|
||||||
])->put('/api/v1/companies/'.$this->encodePrimaryKey($this->company->id), $this->company->toArray());
|
])->putJson('/api/v1/companies/'.$this->encodePrimaryKey($this->company->id), $this->company->toArray());
|
||||||
|
|
||||||
$response->assertStatus(200);
|
$response->assertStatus(200);
|
||||||
|
|
||||||
@ -135,7 +137,7 @@ class CompanySettingsTest extends TestCase
|
|||||||
$response = $this->withHeaders([
|
$response = $this->withHeaders([
|
||||||
'X-API-SECRET' => config('ninja.api_secret'),
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
'X-API-Token' => $this->token,
|
'X-API-Token' => $this->token,
|
||||||
])->put('/api/v1/companies/'.$this->encodePrimaryKey($this->company->id), $this->company->toArray());
|
])->putJson('/api/v1/companies/'.$this->encodePrimaryKey($this->company->id), $this->company->toArray());
|
||||||
|
|
||||||
$response->assertStatus(200);
|
$response->assertStatus(200);
|
||||||
|
|
||||||
@ -162,7 +164,7 @@ class CompanySettingsTest extends TestCase
|
|||||||
$response = $this->withHeaders([
|
$response = $this->withHeaders([
|
||||||
'X-API-SECRET' => config('ninja.api_secret'),
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
'X-API-Token' => $this->token,
|
'X-API-Token' => $this->token,
|
||||||
])->put('/api/v1/companies/'.$this->encodePrimaryKey($this->company->id), $this->company->toArray());
|
])->putJson('/api/v1/companies/'.$this->encodePrimaryKey($this->company->id), $this->company->toArray());
|
||||||
|
|
||||||
$response->assertStatus(200);
|
$response->assertStatus(200);
|
||||||
|
|
||||||
@ -185,7 +187,7 @@ class CompanySettingsTest extends TestCase
|
|||||||
$response = $this->withHeaders([
|
$response = $this->withHeaders([
|
||||||
'X-API-SECRET' => config('ninja.api_secret'),
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
'X-API-Token' => $this->token,
|
'X-API-Token' => $this->token,
|
||||||
])->post('/api/v1/companies?include=company', $this->company->toArray());
|
])->postJson('/api/v1/companies?include=company', $this->company->toArray());
|
||||||
|
|
||||||
$arr = $response->json();
|
$arr = $response->json();
|
||||||
$response->assertStatus(200);
|
$response->assertStatus(200);
|
||||||
@ -203,7 +205,7 @@ class CompanySettingsTest extends TestCase
|
|||||||
$response = $this->withHeaders([
|
$response = $this->withHeaders([
|
||||||
'X-API-SECRET' => config('ninja.api_secret'),
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
'X-API-Token' => $this->token,
|
'X-API-Token' => $this->token,
|
||||||
])->post('/api/v1/companies?include=company', $this->company->toArray());
|
])->postJson('/api/v1/companies?include=company', $this->company->toArray());
|
||||||
|
|
||||||
$arr = $response->json();
|
$arr = $response->json();
|
||||||
$response->assertStatus(200);
|
$response->assertStatus(200);
|
||||||
@ -221,7 +223,7 @@ class CompanySettingsTest extends TestCase
|
|||||||
$response = $this->withHeaders([
|
$response = $this->withHeaders([
|
||||||
'X-API-SECRET' => config('ninja.api_secret'),
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
'X-API-Token' => $this->token,
|
'X-API-Token' => $this->token,
|
||||||
])->post('/api/v1/companies?include=company', $this->company->toArray());
|
])->postJson('/api/v1/companies?include=company', $this->company->toArray());
|
||||||
|
|
||||||
$arr = $response->json();
|
$arr = $response->json();
|
||||||
$response->assertStatus(200);
|
$response->assertStatus(200);
|
||||||
@ -239,7 +241,7 @@ class CompanySettingsTest extends TestCase
|
|||||||
$response = $this->withHeaders([
|
$response = $this->withHeaders([
|
||||||
'X-API-SECRET' => config('ninja.api_secret'),
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
'X-API-Token' => $this->token,
|
'X-API-Token' => $this->token,
|
||||||
])->post('/api/v1/companies?include=company', $this->company->toArray());
|
])->postJson('/api/v1/companies?include=company', $this->company->toArray());
|
||||||
|
|
||||||
$arr = $response->json();
|
$arr = $response->json();
|
||||||
$response->assertStatus(200);
|
$response->assertStatus(200);
|
||||||
|
@ -47,6 +47,31 @@ class PreviewTest extends TestCase
|
|||||||
$response->assertStatus(200);
|
$response->assertStatus(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testPurchaseOrderPreviewRoute()
|
||||||
|
{
|
||||||
|
$data = $this->getData();
|
||||||
|
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
'X-API-TOKEN' => $this->token,
|
||||||
|
])->post('/api/v1/preview/purchase_order', $data);
|
||||||
|
|
||||||
|
$response->assertStatus(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testPurchaseOrderPreviewHtmlResponse()
|
||||||
|
{
|
||||||
|
$data = $this->getData();
|
||||||
|
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
'X-API-TOKEN' => $this->token,
|
||||||
|
])->post('/api/v1/preview/purchase_order?html=true', $data);
|
||||||
|
|
||||||
|
$response->assertStatus(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public function testPreviewHtmlResponse()
|
public function testPreviewHtmlResponse()
|
||||||
{
|
{
|
||||||
$data = $this->getData();
|
$data = $this->getData();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user