mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
Merge branch 'v5-develop' into yodlee
This commit is contained in:
commit
867b960532
@ -1 +1 @@
|
|||||||
5.5.19
|
5.5.25
|
@ -20,6 +20,7 @@ use App\Models\Client;
|
|||||||
use App\Models\ClientContact;
|
use App\Models\ClientContact;
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
use App\Models\CompanyLedger;
|
use App\Models\CompanyLedger;
|
||||||
|
use App\Models\CompanyUser;
|
||||||
use App\Models\Contact;
|
use App\Models\Contact;
|
||||||
use App\Models\Credit;
|
use App\Models\Credit;
|
||||||
use App\Models\CreditInvitation;
|
use App\Models\CreditInvitation;
|
||||||
@ -702,13 +703,23 @@ class CheckData extends Command
|
|||||||
->count();
|
->count();
|
||||||
|
|
||||||
if($count == 0){
|
if($count == 0){
|
||||||
$this->logMessage("# {$client->id} # {$client->name} {$client->balance} is invalid should be 0");
|
|
||||||
|
//factor in over payments to the client balance
|
||||||
|
$over_payment = Payment::where('client_id', $client->id)
|
||||||
|
->where('is_deleted', 0)
|
||||||
|
->whereIn('status_id', [1,4])
|
||||||
|
->selectRaw('sum(amount - applied) as p')
|
||||||
|
->pluck('p')
|
||||||
|
->first();
|
||||||
|
|
||||||
if($this->option('client_balance')){
|
|
||||||
|
$this->logMessage("# {$client->id} # {$client->name} {$client->balance} is invalid should be {$over_payment}");
|
||||||
|
|
||||||
|
if($this->option('client_balance') && (floatval($over_payment) != floatval($client->balance) )){
|
||||||
|
|
||||||
$this->logMessage("# {$client->id} " . $client->present()->name().' - '.$client->number." Fixing {$client->balance} to 0");
|
$this->logMessage("# {$client->id} " . $client->present()->name().' - '.$client->number." Fixing {$client->balance} to 0");
|
||||||
|
|
||||||
$client->balance = 0;
|
$client->balance = $over_payment * -1;
|
||||||
$client->save();
|
$client->save();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
59
app/DataMapper/Analytics/EmailCount.php
Normal file
59
app/DataMapper/Analytics/EmailCount.php
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<?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\DataMapper\Analytics;
|
||||||
|
|
||||||
|
use Turbo124\Beacon\ExampleMetric\GenericMixedMetric;
|
||||||
|
|
||||||
|
class EmailCount extends GenericMixedMetric
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The type of Sample.
|
||||||
|
*
|
||||||
|
* Monotonically incrementing counter
|
||||||
|
*
|
||||||
|
* - counter
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $type = 'mixed_metric';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the counter.
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $name = 'account.daily_email_count';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The datetime of the counter measurement.
|
||||||
|
*
|
||||||
|
* date("Y-m-d H:i:s")
|
||||||
|
*
|
||||||
|
* @var DateTime
|
||||||
|
*/
|
||||||
|
public $datetime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Class failure name
|
||||||
|
* set to 0.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $string_metric5 = 'account_key';
|
||||||
|
|
||||||
|
public $int_metric1 = 1;
|
||||||
|
|
||||||
|
public function __construct($int_metric1, $string_metric5)
|
||||||
|
{
|
||||||
|
$this->int_metric1 = $int_metric1;
|
||||||
|
$this->string_metric5 = $string_metric5;
|
||||||
|
}
|
||||||
|
}
|
@ -26,6 +26,7 @@ class CompanySettings extends BaseSettings
|
|||||||
public $auto_archive_invoice = false; // @implemented
|
public $auto_archive_invoice = false; // @implemented
|
||||||
|
|
||||||
public $qr_iban = ''; //@implemented
|
public $qr_iban = ''; //@implemented
|
||||||
|
|
||||||
public $besr_id = ''; //@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
|
||||||
|
@ -44,6 +44,10 @@ class RecurringExpenseToExpenseFactory
|
|||||||
$expense->payment_date = $recurring_expense->payment_date;
|
$expense->payment_date = $recurring_expense->payment_date;
|
||||||
$expense->amount = $recurring_expense->amount;
|
$expense->amount = $recurring_expense->amount;
|
||||||
$expense->foreign_amount = $recurring_expense->foreign_amount ?: 0;
|
$expense->foreign_amount = $recurring_expense->foreign_amount ?: 0;
|
||||||
|
|
||||||
|
//11-09-2022 - we should be tracking the recurring expense!!
|
||||||
|
$expense->recurring_expense_id = $recurring_expense->id;
|
||||||
|
|
||||||
// $expense->private_notes = $recurring_expense->private_notes;
|
// $expense->private_notes = $recurring_expense->private_notes;
|
||||||
// $expense->public_notes = $recurring_expense->public_notes;
|
// $expense->public_notes = $recurring_expense->public_notes;
|
||||||
|
|
||||||
|
@ -29,10 +29,7 @@ class RecurringInvoiceToInvoiceFactory
|
|||||||
$invoice->terms = self::tranformObject($recurring_invoice->terms, $client);
|
$invoice->terms = self::tranformObject($recurring_invoice->terms, $client);
|
||||||
$invoice->public_notes = self::tranformObject($recurring_invoice->public_notes, $client);
|
$invoice->public_notes = self::tranformObject($recurring_invoice->public_notes, $client);
|
||||||
$invoice->private_notes = $recurring_invoice->private_notes;
|
$invoice->private_notes = $recurring_invoice->private_notes;
|
||||||
//$invoice->date = now()->format($client->date_format());
|
|
||||||
//$invoice->due_date = $recurring_invoice->calculateDueDate(now());
|
|
||||||
$invoice->is_deleted = $recurring_invoice->is_deleted;
|
$invoice->is_deleted = $recurring_invoice->is_deleted;
|
||||||
// $invoice->line_items = $recurring_invoice->line_items;
|
|
||||||
$invoice->line_items = self::transformItems($recurring_invoice, $client);
|
$invoice->line_items = self::transformItems($recurring_invoice, $client);
|
||||||
$invoice->tax_name1 = $recurring_invoice->tax_name1;
|
$invoice->tax_name1 = $recurring_invoice->tax_name1;
|
||||||
$invoice->tax_rate1 = $recurring_invoice->tax_rate1;
|
$invoice->tax_rate1 = $recurring_invoice->tax_rate1;
|
||||||
|
@ -30,7 +30,10 @@ class ClientFilters extends QueryFilters
|
|||||||
*/
|
*/
|
||||||
public function name(string $name): Builder
|
public function name(string $name): Builder
|
||||||
{
|
{
|
||||||
return $this->builder->where('name', 'like', '%'.$name.'%');
|
if(strlen($name) >=1)
|
||||||
|
return $this->builder->where('name', 'like', '%'.$name.'%');
|
||||||
|
|
||||||
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -104,16 +104,39 @@ class SwissQrGenerator
|
|||||||
|
|
||||||
// Add payment reference
|
// Add payment reference
|
||||||
// This is what you will need to identify incoming payments.
|
// 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(
|
if(stripos($this->invoice->number, "Live-") === 0)
|
||||||
QrBill\DataGroup\Element\PaymentReference::create(
|
{
|
||||||
QrBill\DataGroup\Element\PaymentReference::TYPE_QR,
|
// we're currently in preview status. Let's give a dummy reference for now
|
||||||
$referenceNumber
|
$invoice_number = "123456789";
|
||||||
));
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$invoice_number = $this->invoice->number;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strlen($this->company->present()->besr_id()) > 1)
|
||||||
|
{
|
||||||
|
$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.
|
||||||
|
$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
|
||||||
|
));
|
||||||
|
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
|
||||||
|
$qrBill->setPaymentReference(
|
||||||
|
QrBill\DataGroup\Element\PaymentReference::create(
|
||||||
|
QrBill\DataGroup\Element\PaymentReference::TYPE_NON
|
||||||
|
));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// Optionally, add some human-readable information about what the bill is for.
|
// Optionally, add some human-readable information about what the bill is for.
|
||||||
$qrBill->setAdditionalInformation(
|
$qrBill->setAdditionalInformation(
|
||||||
@ -141,6 +164,8 @@ class SwissQrGenerator
|
|||||||
nlog($violation);
|
nlog($violation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nlog($e->getMessage());
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
// return $e->getMessage();
|
// return $e->getMessage();
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ class ActivityController extends BaseController
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @OA\Get(
|
* @OA\Get(
|
||||||
* path="/api/v1/actvities",
|
* path="/api/v1/activities",
|
||||||
* operationId="getActivities",
|
* operationId="getActivities",
|
||||||
* tags={"actvities"},
|
* tags={"actvities"},
|
||||||
* summary="Gets a list of actvities",
|
* summary="Gets a list of actvities",
|
||||||
|
@ -56,7 +56,7 @@ class InvoiceController extends Controller
|
|||||||
{
|
{
|
||||||
set_time_limit(0);
|
set_time_limit(0);
|
||||||
|
|
||||||
$invoice->service()->removeUnpaidGatewayFees()->save();
|
// $invoice->service()->removeUnpaidGatewayFees()->save();
|
||||||
|
|
||||||
$invitation = $invoice->invitations()->where('client_contact_id', auth()->guard('contact')->user()->id)->first();
|
$invitation = $invoice->invitations()->where('client_contact_id', auth()->guard('contact')->user()->id)->first();
|
||||||
|
|
||||||
|
@ -179,7 +179,7 @@ class NinjaPlanController extends Controller
|
|||||||
->queue();
|
->queue();
|
||||||
|
|
||||||
$ninja_company = Company::on('db-ninja-01')->find(config('ninja.ninja_default_company_id'));
|
$ninja_company = Company::on('db-ninja-01')->find(config('ninja.ninja_default_company_id'));
|
||||||
$ninja_company->notification(new NewAccountNotification($account, $client))->ninja();
|
$ninja_company->notification(new NewAccountNotification($subscription->company->account, $client))->ninja();
|
||||||
|
|
||||||
return $this->render('plan.trial_confirmed', $data);
|
return $this->render('plan.trial_confirmed', $data);
|
||||||
}
|
}
|
||||||
|
@ -131,8 +131,10 @@ class EmailController extends BaseController
|
|||||||
if(Ninja::isHosted() && !$entity_obj->company->account->account_sms_verified)
|
if(Ninja::isHosted() && !$entity_obj->company->account->account_sms_verified)
|
||||||
return response(['message' => 'Please verify your account to send emails.'], 400);
|
return response(['message' => 'Please verify your account to send emails.'], 400);
|
||||||
|
|
||||||
if($entity == 'purchaseOrder' || $entity == 'purchase_order' || $template == 'purchase_order'){
|
nlog($entity);
|
||||||
return $this->sendPurchaseOrder($entity_obj, $data);
|
|
||||||
|
if($entity == 'purchaseOrder' || $entity == 'purchase_order' || $template == 'purchase_order' || $entity == 'App\Models\PurchaseOrder'){
|
||||||
|
return $this->sendPurchaseOrder($entity_obj, $data, $template);
|
||||||
}
|
}
|
||||||
|
|
||||||
$entity_obj->invitations->each(function ($invitation) use ($data, $entity_string, $entity_obj, $template) {
|
$entity_obj->invitations->each(function ($invitation) use ($data, $entity_string, $entity_obj, $template) {
|
||||||
@ -183,13 +185,15 @@ class EmailController extends BaseController
|
|||||||
return $this->itemResponse($entity_obj->fresh());
|
return $this->itemResponse($entity_obj->fresh());
|
||||||
}
|
}
|
||||||
|
|
||||||
private function sendPurchaseOrder($entity_obj, $data)
|
private function sendPurchaseOrder($entity_obj, $data, $template)
|
||||||
{
|
{
|
||||||
|
|
||||||
$this->entity_type = PurchaseOrder::class;
|
$this->entity_type = PurchaseOrder::class;
|
||||||
|
|
||||||
$this->entity_transformer = PurchaseOrderTransformer::class;
|
$this->entity_transformer = PurchaseOrderTransformer::class;
|
||||||
|
|
||||||
|
$data['template'] = $template;
|
||||||
|
|
||||||
PurchaseOrderEmail::dispatch($entity_obj, $entity_obj->company, $data);
|
PurchaseOrderEmail::dispatch($entity_obj, $entity_obj->company, $data);
|
||||||
|
|
||||||
return $this->itemResponse($entity_obj);
|
return $this->itemResponse($entity_obj);
|
||||||
|
@ -578,6 +578,16 @@ class InvoiceController extends BaseController
|
|||||||
return response()->json(['message' => ctrans('texts.sent_message')], 200);
|
return response()->json(['message' => ctrans('texts.sent_message')], 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if($action == 'download' && $invoices->count() >=1 && auth()->user()->can('view', $invoices->first())) {
|
||||||
|
|
||||||
|
$file = $invoices->first()->service()->getInvoicePdf();
|
||||||
|
|
||||||
|
return response()->streamDownload(function () use ($file) {
|
||||||
|
echo Storage::get($file);
|
||||||
|
}, basename($file), ['Content-Type' => 'application/pdf']);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Send the other actions to the switch
|
* Send the other actions to the switch
|
||||||
*/
|
*/
|
||||||
|
@ -306,7 +306,7 @@ class PreviewController extends BaseController
|
|||||||
if (Ninja::isHosted()) {
|
if (Ninja::isHosted()) {
|
||||||
LightLogs::create(new LivePreview())
|
LightLogs::create(new LivePreview())
|
||||||
->increment()
|
->increment()
|
||||||
->queue();
|
->batch();
|
||||||
}
|
}
|
||||||
|
|
||||||
$response = Response::make($file_path, 200);
|
$response = Response::make($file_path, 200);
|
||||||
|
@ -292,7 +292,7 @@ class PreviewPurchaseOrderController extends BaseController
|
|||||||
{
|
{
|
||||||
LightLogs::create(new LivePreview())
|
LightLogs::create(new LivePreview())
|
||||||
->increment()
|
->increment()
|
||||||
->queue();
|
->batch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -210,7 +210,7 @@ class RecurringInvoiceController extends BaseController
|
|||||||
|
|
||||||
event(new RecurringInvoiceWasCreated($recurring_invoice, $recurring_invoice->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
|
event(new RecurringInvoiceWasCreated($recurring_invoice, $recurring_invoice->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
|
||||||
|
|
||||||
return $this->itemResponse($recurring_invoice);
|
return $this->itemResponse($recurring_invoice->fresh());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -69,39 +69,7 @@ class SelfUpdateController extends BaseController
|
|||||||
* ),
|
* ),
|
||||||
* )
|
* )
|
||||||
*/
|
*/
|
||||||
// public function old_update(\Codedge\Updater\UpdaterManager $updater)
|
|
||||||
// {
|
|
||||||
// set_time_limit(0);
|
|
||||||
// define('STDIN', fopen('php://stdin', 'r'));
|
|
||||||
|
|
||||||
// if (Ninja::isHosted()) {
|
|
||||||
// return response()->json(['message' => ctrans('texts.self_update_not_available')], 403);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// $this->testWritable();
|
|
||||||
|
|
||||||
// // Get the new version available
|
|
||||||
// $versionAvailable = $updater->source()->getVersionAvailable();
|
|
||||||
|
|
||||||
// // Create a release
|
|
||||||
// $release = $updater->source()->fetch($versionAvailable);
|
|
||||||
|
|
||||||
// $updater->source()->update($release);
|
|
||||||
|
|
||||||
// $cacheCompiled = base_path('bootstrap/cache/compiled.php');
|
|
||||||
// if (file_exists($cacheCompiled)) { unlink ($cacheCompiled); }
|
|
||||||
// $cacheServices = base_path('bootstrap/cache/services.php');
|
|
||||||
// if (file_exists($cacheServices)) { unlink ($cacheServices); }
|
|
||||||
|
|
||||||
// Artisan::call('clear-compiled');
|
|
||||||
// Artisan::call('route:clear');
|
|
||||||
// Artisan::call('view:clear');
|
|
||||||
// Artisan::call('optimize');
|
|
||||||
|
|
||||||
// return response()->json(['message' => 'Update completed'], 200);
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
public function update()
|
public function update()
|
||||||
{
|
{
|
||||||
set_time_limit(0);
|
set_time_limit(0);
|
||||||
|
@ -98,8 +98,6 @@ class Kernel extends HttpKernel
|
|||||||
],
|
],
|
||||||
|
|
||||||
'api' => [
|
'api' => [
|
||||||
// 'throttle:300,1',
|
|
||||||
// 'cors',
|
|
||||||
'bindings',
|
'bindings',
|
||||||
'query_logging',
|
'query_logging',
|
||||||
],
|
],
|
||||||
|
@ -35,7 +35,7 @@ class CreditsTable extends Component
|
|||||||
public function render()
|
public function render()
|
||||||
{
|
{
|
||||||
$query = Credit::query()
|
$query = Credit::query()
|
||||||
->where('client_id', auth()->guard('contact')->user()->client->id)
|
->where('client_id', auth()->guard('contact')->user()->client_id)
|
||||||
->where('company_id', $this->company->id)
|
->where('company_id', $this->company->id)
|
||||||
->where('status_id', '<>', Credit::STATUS_DRAFT)
|
->where('status_id', '<>', Credit::STATUS_DRAFT)
|
||||||
->where('is_deleted', 0)
|
->where('is_deleted', 0)
|
||||||
|
@ -43,10 +43,10 @@ class InvoicesTable extends Component
|
|||||||
$local_status = [];
|
$local_status = [];
|
||||||
|
|
||||||
$query = Invoice::query()
|
$query = Invoice::query()
|
||||||
->with('client.gateway_tokens', 'client.contacts')
|
|
||||||
->orderBy($this->sort_field, $this->sort_asc ? 'asc' : 'desc')
|
|
||||||
->where('company_id', $this->company->id)
|
->where('company_id', $this->company->id)
|
||||||
->where('is_deleted', false);
|
->where('is_deleted', false)
|
||||||
|
->with('client.gateway_tokens', 'client.contacts')
|
||||||
|
->orderBy($this->sort_field, $this->sort_asc ? 'asc' : 'desc');
|
||||||
|
|
||||||
if (in_array('paid', $this->status)) {
|
if (in_array('paid', $this->status)) {
|
||||||
$local_status[] = Invoice::STATUS_PAID;
|
$local_status[] = Invoice::STATUS_PAID;
|
||||||
|
@ -40,9 +40,9 @@ class PaymentsTable extends Component
|
|||||||
{
|
{
|
||||||
$query = Payment::query()
|
$query = Payment::query()
|
||||||
->with('type', 'client')
|
->with('type', 'client')
|
||||||
->whereIn('status_id', [Payment::STATUS_FAILED, Payment::STATUS_COMPLETED, Payment::STATUS_PENDING, Payment::STATUS_REFUNDED, Payment::STATUS_PARTIALLY_REFUNDED])
|
|
||||||
->where('company_id', $this->company->id)
|
->where('company_id', $this->company->id)
|
||||||
->where('client_id', auth()->guard('contact')->user()->client->id)
|
->where('client_id', auth()->guard('contact')->user()->client_id)
|
||||||
|
->whereIn('status_id', [Payment::STATUS_FAILED, Payment::STATUS_COMPLETED, Payment::STATUS_PENDING, Payment::STATUS_REFUNDED, Payment::STATUS_PARTIALLY_REFUNDED])
|
||||||
->orderBy($this->sort_field, $this->sort_asc ? 'asc' : 'desc')
|
->orderBy($this->sort_field, $this->sort_asc ? 'asc' : 'desc')
|
||||||
->withTrashed()
|
->withTrashed()
|
||||||
->paginate($this->per_page);
|
->paginate($this->per_page);
|
||||||
|
@ -45,10 +45,10 @@ class PurchaseOrdersTable extends Component
|
|||||||
|
|
||||||
$query = PurchaseOrder::query()
|
$query = PurchaseOrder::query()
|
||||||
->with('vendor.contacts')
|
->with('vendor.contacts')
|
||||||
->orderBy($this->sort_field, $this->sort_asc ? 'asc' : 'desc')
|
|
||||||
->whereIn('status_id', [PurchaseOrder::STATUS_SENT, PurchaseOrder::STATUS_ACCEPTED])
|
|
||||||
->where('company_id', $this->company->id)
|
->where('company_id', $this->company->id)
|
||||||
->where('is_deleted', false);
|
->whereIn('status_id', [PurchaseOrder::STATUS_SENT, PurchaseOrder::STATUS_ACCEPTED])
|
||||||
|
->where('is_deleted', false)
|
||||||
|
->orderBy($this->sort_field, $this->sort_asc ? 'asc' : 'desc');
|
||||||
|
|
||||||
if (in_array('sent', $this->status)) {
|
if (in_array('sent', $this->status)) {
|
||||||
$local_status[] = PurchaseOrder::STATUS_SENT;
|
$local_status[] = PurchaseOrder::STATUS_SENT;
|
||||||
|
@ -79,9 +79,9 @@ class QuotesTable extends Component
|
|||||||
|
|
||||||
$query = $query
|
$query = $query
|
||||||
->where('company_id', $this->company->id)
|
->where('company_id', $this->company->id)
|
||||||
->where('client_id', auth()->guard('contact')->user()->client->id)
|
->where('client_id', auth()->guard('contact')->user()->client_id)
|
||||||
->where('status_id', '<>', Quote::STATUS_DRAFT)
|
|
||||||
->where('is_deleted', 0)
|
->where('is_deleted', 0)
|
||||||
|
->where('status_id', '<>', Quote::STATUS_DRAFT)
|
||||||
->withTrashed()
|
->withTrashed()
|
||||||
->paginate($this->per_page);
|
->paginate($this->per_page);
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ class RecurringInvoicesTable extends Component
|
|||||||
$query = RecurringInvoice::query();
|
$query = RecurringInvoice::query();
|
||||||
|
|
||||||
$query = $query
|
$query = $query
|
||||||
->where('client_id', auth()->guard('contact')->user()->client->id)
|
->where('client_id', auth()->guard('contact')->user()->client_id)
|
||||||
->where('company_id', $this->company->id)
|
->where('company_id', $this->company->id)
|
||||||
->whereIn('status_id', [RecurringInvoice::STATUS_ACTIVE])
|
->whereIn('status_id', [RecurringInvoice::STATUS_ACTIVE])
|
||||||
->orderBy('status_id', 'asc')
|
->orderBy('status_id', 'asc')
|
||||||
|
@ -14,6 +14,7 @@ namespace App\Http\Livewire;
|
|||||||
|
|
||||||
use App\Libraries\MultiDB;
|
use App\Libraries\MultiDB;
|
||||||
use App\Models\ClientContact;
|
use App\Models\ClientContact;
|
||||||
|
use App\Models\CompanyGateway;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
@ -105,6 +106,8 @@ class RequiredClientInfo extends Component
|
|||||||
|
|
||||||
public $company;
|
public $company;
|
||||||
|
|
||||||
|
public $company_gateway_id;
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
MultiDB::setDb($this->company->db);
|
MultiDB::setDb($this->company->db);
|
||||||
@ -141,6 +144,8 @@ class RequiredClientInfo extends Component
|
|||||||
'client_postal_code' => $this->contact->client->postal_code,
|
'client_postal_code' => $this->contact->client->postal_code,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
//if stripe is enabled, we want to update the customer at this point.
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,6 +155,7 @@ class RequiredClientInfo extends Component
|
|||||||
|
|
||||||
private function updateClientDetails(array $data): bool
|
private function updateClientDetails(array $data): bool
|
||||||
{
|
{
|
||||||
|
nlog($this->company->id);
|
||||||
$client = [];
|
$client = [];
|
||||||
$contact = [];
|
$contact = [];
|
||||||
|
|
||||||
@ -172,6 +178,16 @@ class RequiredClientInfo extends Component
|
|||||||
->push();
|
->push();
|
||||||
|
|
||||||
if ($contact_update && $client_update) {
|
if ($contact_update && $client_update) {
|
||||||
|
|
||||||
|
$cg = CompanyGateway::find($this->company_gateway_id);
|
||||||
|
|
||||||
|
if($cg && $cg->update_details){
|
||||||
|
$payment_gateway = $cg->driver($this->client)->init();
|
||||||
|
|
||||||
|
if(method_exists($payment_gateway, "updateCustomer"))
|
||||||
|
$payment_gateway->updateCustomer();
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ class TasksTable extends Component
|
|||||||
$query = Task::query()
|
$query = Task::query()
|
||||||
->where('company_id', $this->company->id)
|
->where('company_id', $this->company->id)
|
||||||
->where('is_deleted', false)
|
->where('is_deleted', false)
|
||||||
->where('client_id', auth()->guard('contact')->user()->client->id);
|
->where('client_id', auth()->guard('contact')->user()->client_id);
|
||||||
|
|
||||||
if ($this->company->getSetting('show_all_tasks_client_portal') === 'invoiced') {
|
if ($this->company->getSetting('show_all_tasks_client_portal') === 'invoiced') {
|
||||||
$query = $query->whereNotNull('invoice_id');
|
$query = $query->whereNotNull('invoice_id');
|
||||||
|
@ -69,8 +69,8 @@ class QueryLogging
|
|||||||
$ip = request()->ip();
|
$ip = request()->ip();
|
||||||
}
|
}
|
||||||
|
|
||||||
LightLogs::create(new DbQuery($request->method(), urldecode($request->url()), $count, $time, $ip))
|
LightLogs::create(new DbQuery($request->method(), substr(urldecode($request->url()),0,180), $count, $time, $ip))
|
||||||
->queue();
|
->batch();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $response;
|
return $response;
|
||||||
|
@ -158,6 +158,10 @@ class StoreClientRequest extends Request
|
|||||||
unset($input['number']);
|
unset($input['number']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (array_key_exists('name', $input)) {
|
||||||
|
$input['name'] = strip_tags($input['name']);
|
||||||
|
}
|
||||||
|
|
||||||
$this->replace($input);
|
$this->replace($input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,6 +112,10 @@ class UpdateClientRequest extends Request
|
|||||||
$input['settings'] = $this->filterSaveableSettings($input['settings']);
|
$input['settings'] = $this->filterSaveableSettings($input['settings']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (array_key_exists('name', $input)) {
|
||||||
|
$input['name'] = strip_tags($input['name']);
|
||||||
|
}
|
||||||
|
|
||||||
$this->replace($input);
|
$this->replace($input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,15 +65,15 @@ class StoreCompanyRequest extends Request
|
|||||||
$input['google_analytics_key'] = $input['google_analytics_url'];
|
$input['google_analytics_key'] = $input['google_analytics_url'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$company_settings = CompanySettings::defaults();
|
// $company_settings = CompanySettings::defaults();
|
||||||
|
|
||||||
//@todo this code doesn't make sense as we never return $company_settings anywhere
|
//@todo this code doesn't make sense as we never return $company_settings anywhere
|
||||||
//@deprecated???
|
//@deprecated???
|
||||||
if (array_key_exists('settings', $input) && ! empty($input['settings'])) {
|
// if (array_key_exists('settings', $input) && ! empty($input['settings'])) {
|
||||||
foreach ($input['settings'] as $key => $value) {
|
// foreach ($input['settings'] as $key => $value) {
|
||||||
$company_settings->{$key} = $value;
|
// $company_settings->{$key} = $value;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (array_key_exists('portal_domain', $input)) {
|
if (array_key_exists('portal_domain', $input)) {
|
||||||
$input['portal_domain'] = strtolower($input['portal_domain']);
|
$input['portal_domain'] = strtolower($input['portal_domain']);
|
||||||
|
@ -49,7 +49,7 @@ class StoreGroupSettingRequest extends Request
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$input['settings'] = $group_settings;
|
$input['settings'] = (array)$group_settings;
|
||||||
|
|
||||||
$this->replace($input);
|
$this->replace($input);
|
||||||
}
|
}
|
||||||
|
@ -73,6 +73,6 @@ class UpdateGroupSettingRequest extends Request
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $settings;
|
return (array)$settings;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ class StoreInvoiceRequest extends Request
|
|||||||
|
|
||||||
$rules['invitations.*.client_contact_id'] = 'distinct';
|
$rules['invitations.*.client_contact_id'] = 'distinct';
|
||||||
|
|
||||||
$rules['number'] = ['nullable', Rule::unique('invoices')->where('company_id', auth()->user()->company()->id)];
|
$rules['number'] = ['bail', 'nullable', Rule::unique('invoices')->where('company_id', auth()->user()->company()->id)];
|
||||||
|
|
||||||
$rules['project_id'] = ['bail', 'sometimes', new ValidProjectForClient($this->all())];
|
$rules['project_id'] = ['bail', 'sometimes', new ValidProjectForClient($this->all())];
|
||||||
$rules['is_amount_discount'] = ['boolean'];
|
$rules['is_amount_discount'] = ['boolean'];
|
||||||
@ -95,6 +95,9 @@ class StoreInvoiceRequest extends Request
|
|||||||
if (array_key_exists('tax_rate3', $input) && is_null($input['tax_rate3'])) {
|
if (array_key_exists('tax_rate3', $input) && is_null($input['tax_rate3'])) {
|
||||||
$input['tax_rate3'] = 0;
|
$input['tax_rate3'] = 0;
|
||||||
}
|
}
|
||||||
|
if (array_key_exists('exchange_rate', $input) && is_null($input['exchange_rate'])) {
|
||||||
|
$input['exchange_rate'] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
$this->replace($input);
|
$this->replace($input);
|
||||||
}
|
}
|
||||||
|
@ -109,6 +109,7 @@ class StorePaymentRequest extends Request
|
|||||||
'credits.*.amount' => ['bail','required', new CreditsSumRule($this->all())],
|
'credits.*.amount' => ['bail','required', new CreditsSumRule($this->all())],
|
||||||
'invoices' => new ValidPayableInvoicesRule(),
|
'invoices' => new ValidPayableInvoicesRule(),
|
||||||
'number' => ['nullable', 'bail', Rule::unique('payments')->where('company_id', auth()->user()->company()->id)],
|
'number' => ['nullable', 'bail', Rule::unique('payments')->where('company_id', auth()->user()->company()->id)],
|
||||||
|
'idempotency_key' => ['nullable', 'bail', 'string','max:64', Rule::unique('payments')->where('company_id', auth()->user()->company()->id)],
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -85,6 +85,14 @@ class StoreUserRequest extends Request
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (array_key_exists('first_name', $input)) {
|
||||||
|
$input['first_name'] = strip_tags($input['first_name']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array_key_exists('last_name', $input)) {
|
||||||
|
$input['last_name'] = strip_tags($input['last_name']);
|
||||||
|
}
|
||||||
|
|
||||||
$this->replace($input);
|
$this->replace($input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,6 +49,14 @@ class UpdateUserRequest extends Request
|
|||||||
$input['email'] = trim($input['email']);
|
$input['email'] = trim($input['email']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (array_key_exists('first_name', $input)) {
|
||||||
|
$input['first_name'] = strip_tags($input['first_name']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array_key_exists('last_name', $input)) {
|
||||||
|
$input['last_name'] = strip_tags($input['last_name']);
|
||||||
|
}
|
||||||
|
|
||||||
$this->replace($input);
|
$this->replace($input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ class BlackListRule implements Rule
|
|||||||
'arxxwalls.com',
|
'arxxwalls.com',
|
||||||
'superhostforumla.com',
|
'superhostforumla.com',
|
||||||
'wnpop.com',
|
'wnpop.com',
|
||||||
|
'dataservices.space',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -173,18 +173,18 @@ class BaseImport
|
|||||||
$is_free_hosted_client = $this->company->account->isFreeHostedClient();
|
$is_free_hosted_client = $this->company->account->isFreeHostedClient();
|
||||||
$hosted_client_count = $this->company->account->hosted_client_count;
|
$hosted_client_count = $this->company->account->hosted_client_count;
|
||||||
|
|
||||||
|
if($this->factory_name == 'App\Factory\ClientFactory' && $is_free_hosted_client && (count($data) > $hosted_client_count))
|
||||||
|
{
|
||||||
|
$this->error_array[$entity_type][] = [
|
||||||
|
$entity_type => 'client',
|
||||||
|
'error' => 'Error, you are attempting to import more clients than your plan allows',
|
||||||
|
];
|
||||||
|
|
||||||
|
return $count;
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($data as $key => $record) {
|
foreach ($data as $key => $record) {
|
||||||
|
|
||||||
if($this->factory_name instanceof ClientFactory && $is_free_hosted_client && ($this->company->clients()->count() > $hosted_client_count))
|
|
||||||
{
|
|
||||||
$this->error_array[$entity_type][] = [
|
|
||||||
$entity_type => $record,
|
|
||||||
'error' => 'Client limit reached',
|
|
||||||
];
|
|
||||||
|
|
||||||
return $count;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$entity = $this->transformer->transform($record);
|
$entity = $this->transformer->transform($record);
|
||||||
// $validator = $this->request_name::runFormRequest($entity);
|
// $validator = $this->request_name::runFormRequest($entity);
|
||||||
|
@ -178,12 +178,14 @@ class BaseTransformer
|
|||||||
public function getFloat($data, $field)
|
public function getFloat($data, $field)
|
||||||
{
|
{
|
||||||
if (array_key_exists($field, $data)) {
|
if (array_key_exists($field, $data)) {
|
||||||
$number = preg_replace('/[^0-9-.]+/', '', $data[$field]);
|
//$number = preg_replace('/[^0-9-.]+/', '', $data[$field]);
|
||||||
|
return Number::parseStringFloat($data[$field]);
|
||||||
} else {
|
} else {
|
||||||
$number = 0;
|
//$number = 0;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Number::parseFloat($number);
|
// return Number::parseFloat($number);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -86,7 +86,7 @@ class CreateAccount
|
|||||||
$sp794f3f->hosted_company_count = config('ninja.quotas.free.max_companies');
|
$sp794f3f->hosted_company_count = config('ninja.quotas.free.max_companies');
|
||||||
$sp794f3f->account_sms_verified = true;
|
$sp794f3f->account_sms_verified = true;
|
||||||
|
|
||||||
if(in_array($this->getDomain($this->request['email']), ['gmail.com', 'hotmail.com', 'outlook.com', 'yahoo.com'])){
|
if(in_array($this->getDomain($this->request['email']), ['gmail.com', 'hotmail.com', 'outlook.com', 'yahoo.com', 'aol.com', 'mail.ru'])){
|
||||||
$sp794f3f->account_sms_verified = false;
|
$sp794f3f->account_sms_verified = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ namespace App\Jobs\Cron;
|
|||||||
|
|
||||||
use App\Jobs\RecurringInvoice\SendRecurring;
|
use App\Jobs\RecurringInvoice\SendRecurring;
|
||||||
use App\Libraries\MultiDB;
|
use App\Libraries\MultiDB;
|
||||||
|
use App\Models\Invoice;
|
||||||
use App\Models\RecurringInvoice;
|
use App\Models\RecurringInvoice;
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
use Illuminate\Support\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
@ -107,7 +108,7 @@ class RecurringInvoicesCron
|
|||||||
nlog("Trying to send {$recurring_invoice->number}");
|
nlog("Trying to send {$recurring_invoice->number}");
|
||||||
|
|
||||||
if ($recurring_invoice->company->stop_on_unpaid_recurring) {
|
if ($recurring_invoice->company->stop_on_unpaid_recurring) {
|
||||||
if ($recurring_invoice->invoices()->whereIn('status_id', [2, 3])->where('is_deleted', 0)->where('balance', '>', 0)->exists()) {
|
if (Invoice::where('recurring_id', $recurring_invoice->id)->whereIn('status_id', [2, 3])->where('is_deleted', 0)->where('balance', '>', 0)->exists()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ use App\Models\Activity;
|
|||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
use App\Models\CreditInvitation;
|
use App\Models\CreditInvitation;
|
||||||
use App\Models\InvoiceInvitation;
|
use App\Models\InvoiceInvitation;
|
||||||
|
use App\Models\PurchaseOrderInvitation;
|
||||||
use App\Models\QuoteInvitation;
|
use App\Models\QuoteInvitation;
|
||||||
use App\Models\RecurringInvoiceInvitation;
|
use App\Models\RecurringInvoiceInvitation;
|
||||||
use App\Utils\HtmlEngine;
|
use App\Utils\HtmlEngine;
|
||||||
@ -77,12 +78,12 @@ class EmailEntity implements ShouldQueue
|
|||||||
|
|
||||||
$this->invitation = $invitation;
|
$this->invitation = $invitation;
|
||||||
|
|
||||||
$this->settings = $invitation->contact->client->getMergedSettings();
|
|
||||||
|
|
||||||
$this->entity_string = $this->resolveEntityString();
|
$this->entity_string = $this->resolveEntityString();
|
||||||
|
|
||||||
$this->entity = $invitation->{$this->entity_string};
|
$this->entity = $invitation->{$this->entity_string};
|
||||||
|
|
||||||
|
$this->settings = $invitation->contact->client->getMergedSettings();
|
||||||
|
|
||||||
$this->reminder_template = $reminder_template ?: $this->entity->calculateTemplate($this->entity_string);
|
$this->reminder_template = $reminder_template ?: $this->entity->calculateTemplate($this->entity_string);
|
||||||
|
|
||||||
$this->html_engine = new HtmlEngine($invitation);
|
$this->html_engine = new HtmlEngine($invitation);
|
||||||
|
@ -51,7 +51,7 @@ class NinjaMailerJob implements ShouldQueue
|
|||||||
|
|
||||||
public $tries = 3; //number of retries
|
public $tries = 3; //number of retries
|
||||||
|
|
||||||
public $backoff = 10; //seconds to wait until retry
|
public $backoff = 30; //seconds to wait until retry
|
||||||
|
|
||||||
public $deleteWhenMissingModels = true;
|
public $deleteWhenMissingModels = true;
|
||||||
|
|
||||||
@ -123,7 +123,7 @@ class NinjaMailerJob implements ShouldQueue
|
|||||||
->send($this->nmo->mailable);
|
->send($this->nmo->mailable);
|
||||||
|
|
||||||
LightLogs::create(new EmailSuccess($this->nmo->company->company_key))
|
LightLogs::create(new EmailSuccess($this->nmo->company->company_key))
|
||||||
->queue();
|
->batch();
|
||||||
|
|
||||||
/* Count the amount of emails sent across all the users accounts */
|
/* Count the amount of emails sent across all the users accounts */
|
||||||
Cache::increment($this->company->account->key);
|
Cache::increment($this->company->account->key);
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
namespace App\Jobs\Ninja;
|
namespace App\Jobs\Ninja;
|
||||||
|
|
||||||
|
use App\DataMapper\Analytics\EmailCount;
|
||||||
use App\Libraries\MultiDB;
|
use App\Libraries\MultiDB;
|
||||||
use App\Models\Account;
|
use App\Models\Account;
|
||||||
use App\Utils\Ninja;
|
use App\Utils\Ninja;
|
||||||
@ -20,6 +21,7 @@ use Illuminate\Foundation\Bus\Dispatchable;
|
|||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
use Illuminate\Support\Facades\Cache;
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use Turbo124\Beacon\Facades\LightLogs;
|
||||||
|
|
||||||
class AdjustEmailQuota implements ShouldQueue
|
class AdjustEmailQuota implements ShouldQueue
|
||||||
{
|
{
|
||||||
@ -58,8 +60,15 @@ class AdjustEmailQuota implements ShouldQueue
|
|||||||
{
|
{
|
||||||
Account::query()->cursor()->each(function ($account) {
|
Account::query()->cursor()->each(function ($account) {
|
||||||
nlog("resetting email quota for {$account->key}");
|
nlog("resetting email quota for {$account->key}");
|
||||||
|
|
||||||
|
$email_count = Cache::get($account->key);
|
||||||
|
|
||||||
|
if($email_count > 0)
|
||||||
|
LightLogs::create(new EmailCount($email_count, $account->key))->batch();
|
||||||
|
|
||||||
Cache::forget($account->key);
|
Cache::forget($account->key);
|
||||||
Cache::forget("throttle_notified:{$account->key}");
|
Cache::forget("throttle_notified:{$account->key}");
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -217,7 +217,7 @@ class ProcessPostmarkWebhook implements ShouldQueue
|
|||||||
$this->request['MessageID']
|
$this->request['MessageID']
|
||||||
);
|
);
|
||||||
|
|
||||||
LightLogs::create($bounce)->queue();
|
LightLogs::create($bounce)->batch();
|
||||||
|
|
||||||
SystemLogger::dispatch($this->request, SystemLog::CATEGORY_MAIL, SystemLog::EVENT_MAIL_BOUNCED, SystemLog::TYPE_WEBHOOK_RESPONSE, $this->invitation->contact->client, $this->invitation->company);
|
SystemLogger::dispatch($this->request, SystemLog::CATEGORY_MAIL, SystemLog::EVENT_MAIL_BOUNCED, SystemLog::TYPE_WEBHOOK_RESPONSE, $this->invitation->contact->client, $this->invitation->company);
|
||||||
|
|
||||||
@ -263,7 +263,7 @@ class ProcessPostmarkWebhook implements ShouldQueue
|
|||||||
$this->request['MessageID']
|
$this->request['MessageID']
|
||||||
);
|
);
|
||||||
|
|
||||||
LightLogs::create($spam)->queue();
|
LightLogs::create($spam)->batch();
|
||||||
|
|
||||||
SystemLogger::dispatch($this->request, SystemLog::CATEGORY_MAIL, SystemLog::EVENT_MAIL_SPAM_COMPLAINT, SystemLog::TYPE_WEBHOOK_RESPONSE, $this->invitation->contact->client, $this->invitation->company);
|
SystemLogger::dispatch($this->request, SystemLog::CATEGORY_MAIL, SystemLog::EVENT_MAIL_SPAM_COMPLAINT, SystemLog::TYPE_WEBHOOK_RESPONSE, $this->invitation->contact->client, $this->invitation->company);
|
||||||
|
|
||||||
|
@ -77,7 +77,12 @@ class PurchaseOrderEmail implements ShouldQueue
|
|||||||
/* Mark entity sent */
|
/* Mark entity sent */
|
||||||
$invitation->purchase_order->service()->markSent()->save();
|
$invitation->purchase_order->service()->markSent()->save();
|
||||||
|
|
||||||
$email_builder = (new PurchaseOrderEmailEngine($invitation, 'purchase_order', $this->template_data))->build();
|
if(is_array($this->template_data) && array_key_exists('template', $this->template_data))
|
||||||
|
$template = $this->template_data['template'];
|
||||||
|
else
|
||||||
|
$template = 'purchase_order';
|
||||||
|
|
||||||
|
$email_builder = (new PurchaseOrderEmailEngine($invitation, $template, $this->template_data))->build();
|
||||||
|
|
||||||
$nmo = new NinjaMailerObject;
|
$nmo = new NinjaMailerObject;
|
||||||
$nmo->mailable = new VendorTemplateEmail($email_builder, $invitation->contact, $invitation);
|
$nmo->mailable = new VendorTemplateEmail($email_builder, $invitation->contact, $invitation);
|
||||||
@ -86,7 +91,7 @@ class PurchaseOrderEmail implements ShouldQueue
|
|||||||
$nmo->to_user = $invitation->contact;
|
$nmo->to_user = $invitation->contact;
|
||||||
$nmo->entity_string = 'purchase_order';
|
$nmo->entity_string = 'purchase_order';
|
||||||
$nmo->invitation = $invitation;
|
$nmo->invitation = $invitation;
|
||||||
$nmo->reminder_template = 'purchase_order';
|
$nmo->reminder_template = 'email_template_purchase_order';
|
||||||
$nmo->entity = $invitation->purchase_order;
|
$nmo->entity = $invitation->purchase_order;
|
||||||
|
|
||||||
NinjaMailerJob::dispatch($nmo)->delay(5);
|
NinjaMailerJob::dispatch($nmo)->delay(5);
|
||||||
|
@ -73,8 +73,11 @@ class SendRecurring implements ShouldQueue
|
|||||||
$invoice->auto_bill_enabled = false;
|
$invoice->auto_bill_enabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$invoice->date = now()->format('Y-m-d');
|
$invoice->date = date('Y-m-d');
|
||||||
$invoice->due_date = $this->recurring_invoice->calculateDueDate(now()->format('Y-m-d'));
|
|
||||||
|
nlog("Recurring Invoice Date Set on Invoice = {$invoice->date} - ". now()->format('Y-m-d'));
|
||||||
|
|
||||||
|
$invoice->due_date = $this->recurring_invoice->calculateDueDate(date('Y-m-d'));
|
||||||
$invoice->recurring_id = $this->recurring_invoice->id;
|
$invoice->recurring_id = $this->recurring_invoice->id;
|
||||||
$invoice->saveQuietly();
|
$invoice->saveQuietly();
|
||||||
|
|
||||||
@ -96,7 +99,7 @@ class SendRecurring implements ShouldQueue
|
|||||||
/* 09-01-2022 ensure we create the PDFs at this point in time! */
|
/* 09-01-2022 ensure we create the PDFs at this point in time! */
|
||||||
$invoice->service()->touchPdf(true);
|
$invoice->service()->touchPdf(true);
|
||||||
|
|
||||||
nlog('updating recurring invoice dates');
|
//nlog('updating recurring invoice dates');
|
||||||
/* Set next date here to prevent a recurring loop forming */
|
/* Set next date here to prevent a recurring loop forming */
|
||||||
$this->recurring_invoice->next_send_date = $this->recurring_invoice->nextSendDate();
|
$this->recurring_invoice->next_send_date = $this->recurring_invoice->nextSendDate();
|
||||||
$this->recurring_invoice->next_send_date_client = $this->recurring_invoice->nextSendDateClient();
|
$this->recurring_invoice->next_send_date_client = $this->recurring_invoice->nextSendDateClient();
|
||||||
@ -108,9 +111,9 @@ class SendRecurring implements ShouldQueue
|
|||||||
$this->recurring_invoice->setCompleted();
|
$this->recurring_invoice->setCompleted();
|
||||||
}
|
}
|
||||||
|
|
||||||
// nlog('next send date = '.$this->recurring_invoice->next_send_date);
|
//nlog('next send date = '.$this->recurring_invoice->next_send_date);
|
||||||
// nlog('remaining cycles = '.$this->recurring_invoice->remaining_cycles);
|
// nlog('remaining cycles = '.$this->recurring_invoice->remaining_cycles);
|
||||||
// nlog('last send date = '.$this->recurring_invoice->last_sent_date);
|
//nlog('last send date = '.$this->recurring_invoice->last_sent_date);
|
||||||
|
|
||||||
$this->recurring_invoice->save();
|
$this->recurring_invoice->save();
|
||||||
|
|
||||||
|
@ -264,7 +264,7 @@ class Import implements ShouldQueue
|
|||||||
$t->replace(Ninja::transformTranslations($this->company->settings));
|
$t->replace(Ninja::transformTranslations($this->company->settings));
|
||||||
|
|
||||||
Mail::to($this->user->email, $this->user->name())
|
Mail::to($this->user->email, $this->user->name())
|
||||||
->send(new MigrationCompleted($this->company, implode("<br>",$check_data)));
|
->send(new MigrationCompleted($this->company->id, $this->company->db, implode("<br>",$check_data)));
|
||||||
}
|
}
|
||||||
catch(\Exception $e) {
|
catch(\Exception $e) {
|
||||||
nlog($e->getMessage());
|
nlog($e->getMessage());
|
||||||
@ -715,6 +715,15 @@ class Import implements ShouldQueue
|
|||||||
|
|
||||||
Client::reguard();
|
Client::reguard();
|
||||||
|
|
||||||
|
Client::with('contacts')->where('company_id', $this->company->id)->cursor()->each(function ($client){
|
||||||
|
|
||||||
|
$contact = $client->contacts->sortByDesc('is_primary')->first();
|
||||||
|
$contact->is_primary = true;
|
||||||
|
$contact->save();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
/*Improve memory handling by setting everything to null when we have finished*/
|
/*Improve memory handling by setting everything to null when we have finished*/
|
||||||
$data = null;
|
$data = null;
|
||||||
$contact_repository = null;
|
$contact_repository = null;
|
||||||
|
@ -62,7 +62,8 @@ class ReminderJob implements ShouldQueue
|
|||||||
{
|
{
|
||||||
nlog('Sending invoice reminders '.now()->format('Y-m-d h:i:s'));
|
nlog('Sending invoice reminders '.now()->format('Y-m-d h:i:s'));
|
||||||
|
|
||||||
Invoice::where('is_deleted', 0)
|
Invoice::query()
|
||||||
|
->where('is_deleted', 0)
|
||||||
->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL])
|
->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL])
|
||||||
->whereNull('deleted_at')
|
->whereNull('deleted_at')
|
||||||
->where('balance', '>', 0)
|
->where('balance', '>', 0)
|
||||||
|
@ -329,6 +329,24 @@ class MultiDB
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function findAndSetDbByInappTransactionId($transaction_id) :bool
|
||||||
|
{
|
||||||
|
$current_db = config('database.default');
|
||||||
|
|
||||||
|
foreach (self::$dbs as $db) {
|
||||||
|
if (Account::on($db)->where('inapp_transaction_id', $transaction_id)->exists()) {
|
||||||
|
self::setDb($db);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self::setDB($current_db);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static function findAndSetDbByContactKey($contact_key) :bool
|
public static function findAndSetDbByContactKey($contact_key) :bool
|
||||||
{
|
{
|
||||||
$current_db = config('database.default');
|
$current_db = config('database.default');
|
||||||
|
58
app/Listeners/Subscription/AppStoreRenewSubscription.php
Normal file
58
app/Listeners/Subscription/AppStoreRenewSubscription.php
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<?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\Listeners\Subscription;
|
||||||
|
|
||||||
|
use App\Libraries\MultiDB;
|
||||||
|
use App\Models\Account;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Imdhemy\Purchases\Events\AppStore\DidRenew;
|
||||||
|
|
||||||
|
class AppStoreRenewSubscription implements ShouldQueue
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create the event listener.
|
||||||
|
*
|
||||||
|
* @param ActivityRepository $activity_repo
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the event.
|
||||||
|
*
|
||||||
|
* @param object $event
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function handle(DidRenew $event)
|
||||||
|
{
|
||||||
|
|
||||||
|
$inapp_transaction_id = $event->getSubscriptionId(); //$subscription_id
|
||||||
|
|
||||||
|
MultiDB::findAndSetDbByInappTransactionId($inapp_transaction_id);
|
||||||
|
|
||||||
|
$account = Account::where('inapp_transaction_id', $inapp_transaction_id)->first();
|
||||||
|
|
||||||
|
if($account->plan_term == 'month')
|
||||||
|
$account->plan_expires = now()->addMonth();
|
||||||
|
elseif($account->plan_term == 'year')
|
||||||
|
$account->plan_expires = now()->addYear();
|
||||||
|
|
||||||
|
$account->save();
|
||||||
|
|
||||||
|
// $server_notification = $event->getServerNotification();
|
||||||
|
// $subscription = $event->getSubscription();
|
||||||
|
// $subscription_identifier = $event->getSubscriptionIdentifier();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Mail;
|
namespace App\Mail;
|
||||||
|
|
||||||
|
use App\Libraries\MultiDB;
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
use App\Utils\Ninja;
|
use App\Utils\Ninja;
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
@ -13,19 +14,23 @@ class MigrationCompleted extends Mailable
|
|||||||
{
|
{
|
||||||
// use Queueable, SerializesModels;
|
// use Queueable, SerializesModels;
|
||||||
|
|
||||||
public $company;
|
public $company_id;
|
||||||
|
|
||||||
|
public $db;
|
||||||
|
|
||||||
public $check_data;
|
public $check_data;
|
||||||
|
|
||||||
|
public $company;
|
||||||
/**
|
/**
|
||||||
* Create a new message instance.
|
* Create a new message instance.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function __construct(Company $company, $check_data = '')
|
public function __construct(int $company_id, string $db, $check_data = '')
|
||||||
{
|
{
|
||||||
$this->company = $company;
|
$this->company_id = $company_id;
|
||||||
$this->check_data = $check_data;
|
$this->check_data = $check_data;
|
||||||
|
$this->db = $db;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -35,6 +40,10 @@ class MigrationCompleted extends Mailable
|
|||||||
*/
|
*/
|
||||||
public function build()
|
public function build()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
MultiDB::setDb($this->db);
|
||||||
|
$this->company = Company::find($this->company_id);
|
||||||
|
|
||||||
App::forgetInstance('translator');
|
App::forgetInstance('translator');
|
||||||
$t = app('translator');
|
$t = app('translator');
|
||||||
$t->replace(Ninja::transformTranslations($this->company->settings));
|
$t->replace(Ninja::transformTranslations($this->company->settings));
|
||||||
|
@ -8,6 +8,7 @@ use Illuminate\Mail\Mailable;
|
|||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
use LimitIterator;
|
use LimitIterator;
|
||||||
use SplFileObject;
|
use SplFileObject;
|
||||||
|
use Illuminate\Support\Carbon;
|
||||||
|
|
||||||
class SupportMessageSent extends Mailable
|
class SupportMessageSent extends Mailable
|
||||||
{
|
{
|
||||||
@ -72,8 +73,8 @@ class SupportMessageSent extends Mailable
|
|||||||
|
|
||||||
$plan_status = '';
|
$plan_status = '';
|
||||||
|
|
||||||
if(Carbon::parse($account->plan_expires)->lt(now()))
|
if($account->plan_expires && Carbon::parse($account->plan_expires)->lt(now()))
|
||||||
$plan_status = 'Plan Expired';
|
$plan_status = 'Plan Expired :: ';
|
||||||
|
|
||||||
if (Ninja::isHosted()) {
|
if (Ninja::isHosted()) {
|
||||||
$subject = "{$priority}Hosted-{$db}-{$is_large}{$platform}{$migrated}{$trial} :: {$plan} :: {$plan_status} ".date('M jS, g:ia');
|
$subject = "{$priority}Hosted-{$db}-{$is_large}{$platform}{$migrated}{$trial} :: {$plan} :: {$plan_status} ".date('M jS, g:ia');
|
||||||
|
@ -61,7 +61,7 @@ class VendorTemplateEmail extends Mailable
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($this->build_email->getTemplate() == 'custom') {
|
if ($this->build_email->getTemplate() == 'custom') {
|
||||||
$this->build_email->setBody(str_replace('$body', $this->build_email->getBody(), $this->client->getSetting('email_style_custom')));
|
$this->build_email->setBody(str_replace('$body', $this->build_email->getBody(), $this->company->getSetting('email_style_custom')));
|
||||||
}
|
}
|
||||||
|
|
||||||
$settings = $this->company->settings;
|
$settings = $this->company->settings;
|
||||||
|
@ -613,19 +613,19 @@ class Client extends BaseModel implements HasLocalePreference
|
|||||||
{
|
{
|
||||||
$defaults = [];
|
$defaults = [];
|
||||||
|
|
||||||
if (! (array_key_exists('terms', $data) && strlen($data['terms']) > 1)) {
|
if (! (array_key_exists('terms', $data) && is_string($data['terms']) && strlen($data['terms']) > 1)) {
|
||||||
$defaults['terms'] = $this->getSetting($entity_name.'_terms');
|
$defaults['terms'] = $this->getSetting($entity_name.'_terms');
|
||||||
} elseif (array_key_exists('terms', $data)) {
|
} elseif (array_key_exists('terms', $data)) {
|
||||||
$defaults['terms'] = $data['terms'];
|
$defaults['terms'] = $data['terms'];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! (array_key_exists('footer', $data) && strlen($data['footer']) > 1)) {
|
if (! (array_key_exists('footer', $data) && is_string($data['footer']) && strlen($data['footer']) > 1)) {
|
||||||
$defaults['footer'] = $this->getSetting($entity_name.'_footer');
|
$defaults['footer'] = $this->getSetting($entity_name.'_footer');
|
||||||
} elseif (array_key_exists('footer', $data)) {
|
} elseif (array_key_exists('footer', $data)) {
|
||||||
$defaults['footer'] = $data['footer'];
|
$defaults['footer'] = $data['footer'];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strlen($this->public_notes) >= 1) {
|
if (is_string($this->public_notes) && strlen($this->public_notes) >= 1) {
|
||||||
$defaults['public_notes'] = $this->public_notes;
|
$defaults['public_notes'] = $this->public_notes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,6 +122,7 @@ class Company extends BaseModel
|
|||||||
'stock_notification',
|
'stock_notification',
|
||||||
'enabled_expense_tax_rates',
|
'enabled_expense_tax_rates',
|
||||||
'invoice_task_project',
|
'invoice_task_project',
|
||||||
|
'report_include_deleted',
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $hidden = [
|
protected $hidden = [
|
||||||
|
@ -560,7 +560,7 @@ class RecurringInvoice extends BaseModel
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'on_receipt':
|
case 'on_receipt':
|
||||||
return Carbon::Parse($date)->copy();
|
return Carbon::parse($date)->copy();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -64,7 +64,7 @@ class Vendor extends BaseModel
|
|||||||
protected $touches = [];
|
protected $touches = [];
|
||||||
|
|
||||||
protected $with = [
|
protected $with = [
|
||||||
'company',
|
'contacts.company',
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $presenter = VendorPresenter::class;
|
protected $presenter = VendorPresenter::class;
|
||||||
@ -108,12 +108,13 @@ class Vendor extends BaseModel
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (! $this->currency_id) {
|
if (! $this->currency_id) {
|
||||||
$this->currency_id = 1;
|
return $this->company->currency();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $currencies->filter(function ($item) {
|
return $currencies->filter(function ($item) {
|
||||||
return $item->id == $this->currency_id;
|
return $item->id == $this->currency_id;
|
||||||
})->first();
|
})->first();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function company()
|
public function company()
|
||||||
|
@ -45,10 +45,7 @@ class VendorContact extends Authenticatable implements HasLocalePreference
|
|||||||
'hashed_id',
|
'hashed_id',
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $with = [
|
protected $with = [];
|
||||||
// 'vendor',
|
|
||||||
// 'company'
|
|
||||||
];
|
|
||||||
|
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
'updated_at' => 'timestamp',
|
'updated_at' => 'timestamp',
|
||||||
|
@ -70,6 +70,12 @@ class Webhook extends BaseModel
|
|||||||
|
|
||||||
const EVENT_PROJECT_UPDATE = 26;
|
const EVENT_PROJECT_UPDATE = 26;
|
||||||
|
|
||||||
|
const EVENT_CREATE_CREDIT = 27;
|
||||||
|
|
||||||
|
const EVENT_UPDATE_CREDIT = 28;
|
||||||
|
|
||||||
|
const EVENT_DELETE_CREDIT = 29;
|
||||||
|
|
||||||
public static $valid_events = [
|
public static $valid_events = [
|
||||||
self::EVENT_CREATE_CLIENT,
|
self::EVENT_CREATE_CLIENT,
|
||||||
self::EVENT_CREATE_INVOICE,
|
self::EVENT_CREATE_INVOICE,
|
||||||
@ -97,6 +103,9 @@ class Webhook extends BaseModel
|
|||||||
self::EVENT_REMIND_INVOICE,
|
self::EVENT_REMIND_INVOICE,
|
||||||
self::EVENT_PROJECT_CREATE,
|
self::EVENT_PROJECT_CREATE,
|
||||||
self::EVENT_PROJECT_UPDATE,
|
self::EVENT_PROJECT_UPDATE,
|
||||||
|
self::EVENT_CREATE_CREDIT,
|
||||||
|
self::EVENT_UPDATE_CREDIT,
|
||||||
|
self::EVENT_DELETE_CREDIT,
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
|
@ -27,6 +27,13 @@ class CreditObserver
|
|||||||
*/
|
*/
|
||||||
public function created(Credit $credit)
|
public function created(Credit $credit)
|
||||||
{
|
{
|
||||||
|
$subscriptions = Webhook::where('company_id', $credit->company->id)
|
||||||
|
->where('event_id', Webhook::EVENT_CREATE_CREDIT)
|
||||||
|
->exists();
|
||||||
|
|
||||||
|
if ($subscriptions) {
|
||||||
|
WebhookHandler::dispatch(Webhook::EVENT_CREATE_CREDIT, $credit, $credit->company)->delay(now()->addSeconds(2));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -37,6 +44,13 @@ class CreditObserver
|
|||||||
*/
|
*/
|
||||||
public function updated(Credit $credit)
|
public function updated(Credit $credit)
|
||||||
{
|
{
|
||||||
|
$subscriptions = Webhook::where('company_id', $credit->company->id)
|
||||||
|
->where('event_id', Webhook::EVENT_UPDATE_CREDIT)
|
||||||
|
->exists();
|
||||||
|
|
||||||
|
if ($subscriptions) {
|
||||||
|
WebhookHandler::dispatch(Webhook::EVENT_UPDATE_CREDIT, $credit, $credit->company)->delay(now()->addSeconds(2));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -47,6 +61,13 @@ class CreditObserver
|
|||||||
*/
|
*/
|
||||||
public function deleted(Credit $credit)
|
public function deleted(Credit $credit)
|
||||||
{
|
{
|
||||||
|
$subscriptions = Webhook::where('company_id', $credit->company->id)
|
||||||
|
->where('event_id', Webhook::EVENT_DELETE_CREDIT)
|
||||||
|
->exists();
|
||||||
|
|
||||||
|
if ($subscriptions) {
|
||||||
|
WebhookHandler::dispatch(Webhook::EVENT_DELETE_CREDIT, $credit, $credit->company)->delay(now()->addSeconds(2));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -39,6 +39,7 @@ class CreditCard
|
|||||||
public function authorizeView(array $data)
|
public function authorizeView(array $data)
|
||||||
{
|
{
|
||||||
$data['gateway'] = $this->braintree;
|
$data['gateway'] = $this->braintree;
|
||||||
|
$data['threeds_enable'] = $this->braintree->company_gateway->getConfigField('threeds') ? "true" : "false";
|
||||||
|
|
||||||
return render('gateways.braintree.credit_card.authorize', $data);
|
return render('gateways.braintree.credit_card.authorize', $data);
|
||||||
}
|
}
|
||||||
@ -54,11 +55,32 @@ class CreditCard
|
|||||||
* @param array $data
|
* @param array $data
|
||||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
private function threeDParameters(array $data)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'amount' => $data['amount_with_fee'],
|
||||||
|
'email' => $this->braintree->client->present()->email(),
|
||||||
|
'billingAddress' => [
|
||||||
|
'givenName' => $this->braintree->client->present()->first_name() ?: $this->braintree->client->present()->name(),
|
||||||
|
'surname' => $this->braintree->client->present()->last_name() ?: '',
|
||||||
|
'phoneNumber' => $this->braintree->client->present()->phone(),
|
||||||
|
'streetAddress' => $this->braintree->client->address1 ?: '',
|
||||||
|
'extendedAddress' =>$this->braintree->client->address2 ?: '',
|
||||||
|
'locality' => $this->braintree->client->city ?: '',
|
||||||
|
'postalCode' => $this->braintree->client->postal_code ?: '',
|
||||||
|
'countryCodeAlpha2' => $this->braintree->client->country ? $this->braintree->client->country->iso_3166_2 : 'US',
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
public function paymentView(array $data)
|
public function paymentView(array $data)
|
||||||
{
|
{
|
||||||
$data['gateway'] = $this->braintree;
|
$data['gateway'] = $this->braintree;
|
||||||
$data['client_token'] = $this->braintree->gateway->clientToken()->generate();
|
$data['client_token'] = $this->braintree->gateway->clientToken()->generate();
|
||||||
|
$data['threeds'] = $this->threeDParameters($data);
|
||||||
|
$data['threeds_enable'] = $this->braintree->company_gateway->getConfigField('threeds') ? "true" : "false";
|
||||||
|
|
||||||
if ($this->braintree->company_gateway->getConfigField('merchantAccountId')) {
|
if ($this->braintree->company_gateway->getConfigField('merchantAccountId')) {
|
||||||
/** https://developer.paypal.com/braintree/docs/reference/request/client-token/generate#merchant_account_id */
|
/** https://developer.paypal.com/braintree/docs/reference/request/client-token/generate#merchant_account_id */
|
||||||
$data['client_token'] = $this->braintree->gateway->clientToken()->generate([
|
$data['client_token'] = $this->braintree->gateway->clientToken()->generate([
|
||||||
@ -78,6 +100,8 @@ class CreditCard
|
|||||||
*/
|
*/
|
||||||
public function paymentResponse(PaymentResponseRequest $request)
|
public function paymentResponse(PaymentResponseRequest $request)
|
||||||
{
|
{
|
||||||
|
// nlog($request->all());
|
||||||
|
|
||||||
$state = [
|
$state = [
|
||||||
'server_response' => json_decode($request->gateway_response),
|
'server_response' => json_decode($request->gateway_response),
|
||||||
'payment_hash' => $request->payment_hash,
|
'payment_hash' => $request->payment_hash,
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
namespace App\PaymentDrivers;
|
namespace App\PaymentDrivers;
|
||||||
|
|
||||||
|
use App\Exceptions\PaymentFailed;
|
||||||
use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest;
|
use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest;
|
||||||
use App\Http\Requests\Gateways\Checkout3ds\Checkout3dsRequest;
|
use App\Http\Requests\Gateways\Checkout3ds\Checkout3dsRequest;
|
||||||
use App\Http\Requests\Payments\PaymentWebhookRequest;
|
use App\Http\Requests\Payments\PaymentWebhookRequest;
|
||||||
@ -33,7 +34,8 @@ use Checkout\CheckoutArgumentException;
|
|||||||
use Checkout\CheckoutAuthorizationException;
|
use Checkout\CheckoutAuthorizationException;
|
||||||
use Checkout\CheckoutDefaultSdk;
|
use Checkout\CheckoutDefaultSdk;
|
||||||
use Checkout\CheckoutFourSdk;
|
use Checkout\CheckoutFourSdk;
|
||||||
use Checkout\Common\CustomerRequest;
|
use Checkout\Customers\CustomerRequest;
|
||||||
|
use Checkout\Customers\Four\CustomerRequest as FourCustomerRequest;
|
||||||
use Checkout\Environment;
|
use Checkout\Environment;
|
||||||
use Checkout\Library\Exceptions\CheckoutHttpException;
|
use Checkout\Library\Exceptions\CheckoutHttpException;
|
||||||
use Checkout\Models\Payments\IdSource;
|
use Checkout\Models\Payments\IdSource;
|
||||||
@ -253,12 +255,13 @@ class CheckoutComPaymentDriver extends BaseDriver
|
|||||||
];
|
];
|
||||||
} catch (CheckoutApiException $e) {
|
} catch (CheckoutApiException $e) {
|
||||||
// API error
|
// API error
|
||||||
$request_id = $e->request_id;
|
throw new PaymentFailed($e->getMessage(), $e->getCode());
|
||||||
$http_status_code = $e->http_status_code;
|
|
||||||
$error_details = $e->error_details;
|
|
||||||
} catch (CheckoutArgumentException $e) {
|
} catch (CheckoutArgumentException $e) {
|
||||||
// Bad arguments
|
// Bad arguments
|
||||||
|
|
||||||
|
throw new PaymentFailed($e->getMessage(), $e->getCode());
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'transaction_reference' => null,
|
'transaction_reference' => null,
|
||||||
'transaction_response' => json_encode($e->getMessage()),
|
'transaction_response' => json_encode($e->getMessage()),
|
||||||
@ -269,6 +272,8 @@ class CheckoutComPaymentDriver extends BaseDriver
|
|||||||
} catch (CheckoutAuthorizationException $e) {
|
} catch (CheckoutAuthorizationException $e) {
|
||||||
// Bad Invalid authorization
|
// Bad Invalid authorization
|
||||||
|
|
||||||
|
throw new PaymentFailed($e->getMessage(), $e->getCode());
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'transaction_reference' => null,
|
'transaction_reference' => null,
|
||||||
'transaction_response' => json_encode($e->getMessage()),
|
'transaction_response' => json_encode($e->getMessage()),
|
||||||
@ -285,12 +290,28 @@ class CheckoutComPaymentDriver extends BaseDriver
|
|||||||
$response = $this->gateway->getCustomersClient()->get($this->client->present()->email());
|
$response = $this->gateway->getCustomersClient()->get($this->client->present()->email());
|
||||||
|
|
||||||
return $response;
|
return $response;
|
||||||
|
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$request = new CustomerRequest();
|
|
||||||
|
if ($this->is_four_api) {
|
||||||
|
$request = new FourCustomerRequest();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
$request = new CustomerRequest();
|
||||||
|
}
|
||||||
|
|
||||||
$request->email = $this->client->present()->email();
|
$request->email = $this->client->present()->email();
|
||||||
$request->name = $this->client->present()->name();
|
$request->name = $this->client->present()->name();
|
||||||
|
$request->phone = $this->client->present()->phone();
|
||||||
|
|
||||||
return $request;
|
try {
|
||||||
|
$response = $this->gateway->getCustomersClient()->create($request);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
// API error
|
||||||
|
throw new PaymentFailed($e->getMessage(), $e->getCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,7 +261,7 @@ class GoCardlessPaymentDriver extends BaseDriver
|
|||||||
//finalize payments on invoices here.
|
//finalize payments on invoices here.
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($event['action'] === 'failed') {
|
if ($event['action'] === 'failed' && array_key_exists('payment', $event['links'])) {
|
||||||
$payment = Payment::query()
|
$payment = Payment::query()
|
||||||
->where('transaction_reference', $event['links']['payment'])
|
->where('transaction_reference', $event['links']['payment'])
|
||||||
->where('company_id', $request->getCompany()->id)
|
->where('company_id', $request->getCompany()->id)
|
||||||
|
@ -125,6 +125,20 @@ class ACH
|
|||||||
|
|
||||||
$bank_account = Customer::retrieveSource($request->customer, $request->source, [], $this->stripe->stripe_connect_auth);
|
$bank_account = Customer::retrieveSource($request->customer, $request->source, [], $this->stripe->stripe_connect_auth);
|
||||||
|
|
||||||
|
/* Catch externally validated bank accounts and mark them as verified */
|
||||||
|
if(property_exists($bank_account, 'status') && $bank_account->status == 'verified'){
|
||||||
|
|
||||||
|
$meta = $token->meta;
|
||||||
|
$meta->state = 'authorized';
|
||||||
|
$token->meta = $meta;
|
||||||
|
$token->save();
|
||||||
|
|
||||||
|
return redirect()
|
||||||
|
->route('client.payment_methods.show', $token->hashed_id)
|
||||||
|
->with('message', __('texts.payment_method_verified'));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$bank_account->verify(['amounts' => request()->transactions]);
|
$bank_account->verify(['amounts' => request()->transactions]);
|
||||||
|
|
||||||
|
@ -17,11 +17,12 @@ use App\Jobs\Util\SystemLogger;
|
|||||||
use App\Models\ClientGatewayToken;
|
use App\Models\ClientGatewayToken;
|
||||||
use App\Models\GatewayType;
|
use App\Models\GatewayType;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
|
use App\Models\Payment;
|
||||||
use App\Models\PaymentHash;
|
use App\Models\PaymentHash;
|
||||||
use App\Models\PaymentType;
|
use App\Models\PaymentType;
|
||||||
use App\Models\SystemLog;
|
use App\Models\SystemLog;
|
||||||
use App\PaymentDrivers\Stripe\ACH;
|
|
||||||
use App\PaymentDrivers\StripePaymentDriver;
|
use App\PaymentDrivers\StripePaymentDriver;
|
||||||
|
use App\PaymentDrivers\Stripe\ACH;
|
||||||
use App\Utils\Ninja;
|
use App\Utils\Ninja;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
use Stripe\Exception\ApiConnectionException;
|
use Stripe\Exception\ApiConnectionException;
|
||||||
@ -137,8 +138,10 @@ class Charge
|
|||||||
|
|
||||||
if ($cgt->gateway_type_id == GatewayType::SEPA) {
|
if ($cgt->gateway_type_id == GatewayType::SEPA) {
|
||||||
$payment_method_type = PaymentType::SEPA;
|
$payment_method_type = PaymentType::SEPA;
|
||||||
|
$status = Payment::STATUS_PENDING;
|
||||||
} else {
|
} else {
|
||||||
$payment_method_type = $response->charges->data[0]->payment_method_details->card->brand;
|
$payment_method_type = $response->charges->data[0]->payment_method_details->card->brand;
|
||||||
|
$status = Payment::STATUS_COMPLETED;
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
@ -148,7 +151,7 @@ class Charge
|
|||||||
'amount' => $amount,
|
'amount' => $amount,
|
||||||
];
|
];
|
||||||
|
|
||||||
$payment = $this->stripe->createPayment($data);
|
$payment = $this->stripe->createPayment($data, $status);
|
||||||
$payment->meta = $cgt->meta;
|
$payment->meta = $cgt->meta;
|
||||||
$payment->save();
|
$payment->save();
|
||||||
|
|
||||||
|
@ -58,12 +58,12 @@ class UpdateCustomer implements ShouldQueue
|
|||||||
|
|
||||||
$company = Company::where('company_key', $this->company_key)->first();
|
$company = Company::where('company_key', $this->company_key)->first();
|
||||||
|
|
||||||
if($company->id !== config('ninja.ninja_default_company_id'))
|
|
||||||
return;
|
|
||||||
|
|
||||||
$company_gateway = CompanyGateway::find($this->company_gateway_id);
|
$company_gateway = CompanyGateway::find($this->company_gateway_id);
|
||||||
$client = Client::withTrashed()->find($this->client_id);
|
$client = Client::withTrashed()->find($this->client_id);
|
||||||
|
|
||||||
|
if(!$company_gateway->update_details)
|
||||||
|
return;
|
||||||
|
|
||||||
$stripe = $company_gateway->driver($client)->init();
|
$stripe = $company_gateway->driver($client)->init();
|
||||||
|
|
||||||
$customer = $stripe->findOrCreateCustomer();
|
$customer = $stripe->findOrCreateCustomer();
|
||||||
|
@ -39,6 +39,7 @@ class SEPA
|
|||||||
$data['client'] = $this->stripe->client;
|
$data['client'] = $this->stripe->client;
|
||||||
$data['country'] = $this->stripe->client->country->iso_3166_2;
|
$data['country'] = $this->stripe->client->country->iso_3166_2;
|
||||||
$data['currency'] = $this->stripe->client->currency();
|
$data['currency'] = $this->stripe->client->currency();
|
||||||
|
$data['payment_hash'] = 'x';
|
||||||
|
|
||||||
return render('gateways.stripe.sepa.authorize', $data);
|
return render('gateways.stripe.sepa.authorize', $data);
|
||||||
}
|
}
|
||||||
|
@ -74,7 +74,7 @@ class UpdatePaymentMethods
|
|||||||
{
|
{
|
||||||
$sources = $customer->sources;
|
$sources = $customer->sources;
|
||||||
|
|
||||||
if(!property_exists($sources, 'data'))
|
if(!$customer || !property_exists($sources, 'data'))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
foreach ($sources->data as $method) {
|
foreach ($sources->data as $method) {
|
||||||
|
@ -511,6 +511,36 @@ class StripePaymentDriver extends BaseDriver
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function updateCustomer()
|
||||||
|
{
|
||||||
|
if($this->client)
|
||||||
|
{
|
||||||
|
|
||||||
|
$customer = $this->findOrCreateCustomer();
|
||||||
|
//Else create a new record
|
||||||
|
$data['name'] = $this->client->present()->name();
|
||||||
|
$data['phone'] = substr($this->client->present()->phone(), 0, 20);
|
||||||
|
|
||||||
|
$data['address']['line1'] = $this->client->address1;
|
||||||
|
$data['address']['line2'] = $this->client->address2;
|
||||||
|
$data['address']['city'] = $this->client->city;
|
||||||
|
$data['address']['postal_code'] = $this->client->postal_code;
|
||||||
|
$data['address']['state'] = $this->client->state;
|
||||||
|
$data['address']['country'] = $this->client->country ? $this->client->country->iso_3166_2 : '';
|
||||||
|
|
||||||
|
$data['shipping']['name'] = $this->client->present()->name();
|
||||||
|
$data['shipping']['address']['line1'] = $this->client->shipping_address1;
|
||||||
|
$data['shipping']['address']['line2'] = $this->client->shipping_address2;
|
||||||
|
$data['shipping']['address']['city'] = $this->client->shipping_city;
|
||||||
|
$data['shipping']['address']['postal_code'] = $this->client->shipping_postal_code;
|
||||||
|
$data['shipping']['address']['state'] = $this->client->shipping_state;
|
||||||
|
$data['shipping']['address']['country'] = $this->client->shipping_country ? $this->client->shipping_country->iso_3166_2 : '';
|
||||||
|
|
||||||
|
\Stripe\Customer::update($customer->id, $data, $this->stripe_connect_auth);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function refund(Payment $payment, $amount, $return_client_response = false)
|
public function refund(Payment $payment, $amount, $return_client_response = false)
|
||||||
{
|
{
|
||||||
$this->init();
|
$this->init();
|
||||||
|
@ -41,6 +41,7 @@ class ACH
|
|||||||
public function authorizeView($data)
|
public function authorizeView($data)
|
||||||
{
|
{
|
||||||
$data['gateway'] = $this->wepay_payment_driver;
|
$data['gateway'] = $this->wepay_payment_driver;
|
||||||
|
$data['country_code'] = $this->wepay_payment_driver->client ? $this->wepay_payment_driver->client->country->iso_3166_2 : $this->wepay_payment_driver->company_gateway->company()->iso_3166_2;
|
||||||
|
|
||||||
return render('gateways.wepay.authorize.bank_transfer', $data);
|
return render('gateways.wepay.authorize.bank_transfer', $data);
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,7 @@ class CreditCard
|
|||||||
public function authorizeView($data)
|
public function authorizeView($data)
|
||||||
{
|
{
|
||||||
$data['gateway'] = $this->wepay_payment_driver;
|
$data['gateway'] = $this->wepay_payment_driver;
|
||||||
|
$data['country_code'] = $this->wepay_payment_driver->client ? $this->wepay_payment_driver->client->country->iso_3166_2 : $this->wepay_payment_driver->company_gateway->company()->iso_3166_2;
|
||||||
|
|
||||||
return render('gateways.wepay.authorize.authorize', $data);
|
return render('gateways.wepay.authorize.authorize', $data);
|
||||||
}
|
}
|
||||||
@ -101,6 +102,7 @@ class CreditCard
|
|||||||
{
|
{
|
||||||
$data['gateway'] = $this->wepay_payment_driver;
|
$data['gateway'] = $this->wepay_payment_driver;
|
||||||
$data['description'] = ctrans('texts.invoices').': '.collect($data['invoices'])->pluck('invoice_number');
|
$data['description'] = ctrans('texts.invoices').': '.collect($data['invoices'])->pluck('invoice_number');
|
||||||
|
$data['country_code'] = $this->wepay_payment_driver->client ? $this->wepay_payment_driver->client->country->iso_3166_2 : $this->wepay_payment_driver->company_gateway->company()->iso_3166_2;
|
||||||
|
|
||||||
return render('gateways.wepay.credit_card.pay', $data);
|
return render('gateways.wepay.credit_card.pay', $data);
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ class EntityPolicy
|
|||||||
public function edit(User $user, $entity) : bool
|
public function edit(User $user, $entity) : bool
|
||||||
{
|
{
|
||||||
return ($user->isAdmin() && $entity->company_id == $user->companyId())
|
return ($user->isAdmin() && $entity->company_id == $user->companyId())
|
||||||
|| ($user->hasPermission('edit_'.strtolower(class_basename($entity))) && $entity->company_id == $user->companyId())
|
|| ($user->hasPermission('edit_'.strtolower(\Illuminate\Support\Str::snake(class_basename($entity)))) && $entity->company_id == $user->companyId())
|
||||||
|| ($user->hasPermission('edit_all') && $entity->company_id == $user->companyId())
|
|| ($user->hasPermission('edit_all') && $entity->company_id == $user->companyId())
|
||||||
|| $user->owns($entity)
|
|| $user->owns($entity)
|
||||||
|| $user->assigned($entity);
|
|| $user->assigned($entity);
|
||||||
@ -64,7 +64,7 @@ class EntityPolicy
|
|||||||
public function view(User $user, $entity) : bool
|
public function view(User $user, $entity) : bool
|
||||||
{
|
{
|
||||||
return ($user->isAdmin() && $entity->company_id == $user->companyId())
|
return ($user->isAdmin() && $entity->company_id == $user->companyId())
|
||||||
|| ($user->hasPermission('view_'.strtolower(class_basename($entity))) && $entity->company_id == $user->companyId())
|
|| ($user->hasPermission('view_'.strtolower(\Illuminate\Support\Str::snake(class_basename($entity)))) && $entity->company_id == $user->companyId())
|
||||||
|| ($user->hasPermission('view_all') && $entity->company_id == $user->companyId())
|
|| ($user->hasPermission('view_all') && $entity->company_id == $user->companyId())
|
||||||
|| $user->owns($entity)
|
|| $user->owns($entity)
|
||||||
|| $user->assigned($entity);
|
|| $user->assigned($entity);
|
||||||
|
@ -304,7 +304,9 @@ class BaseRepository
|
|||||||
|
|
||||||
if (($state['finished_amount'] != $state['starting_amount']) && ($model->status_id != Invoice::STATUS_DRAFT)) {
|
if (($state['finished_amount'] != $state['starting_amount']) && ($model->status_id != Invoice::STATUS_DRAFT)) {
|
||||||
|
|
||||||
//10-07-2022
|
//14-09-2022 log when we make changes to the invoice balance.
|
||||||
|
nlog("Adjustment - {$model->number} - " .$state['finished_amount']. " - " . $state['starting_amount']);
|
||||||
|
|
||||||
$model->service()->updateStatus()->save();
|
$model->service()->updateStatus()->save();
|
||||||
$model->client->service()->updateBalance(($state['finished_amount'] - $state['starting_amount']))->save();
|
$model->client->service()->updateBalance(($state['finished_amount'] - $state['starting_amount']))->save();
|
||||||
$model->ledger()->updateInvoiceBalance(($state['finished_amount'] - $state['starting_amount']), "Update adjustment for invoice {$model->number}");
|
$model->ledger()->updateInvoiceBalance(($state['finished_amount'] - $state['starting_amount']), "Update adjustment for invoice {$model->number}");
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoice Ninja (https://invoiceninja.com).
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
*
|
*
|
||||||
@ -16,6 +17,7 @@ use App\Libraries\Currency\Conversion\CurrencyApi;
|
|||||||
use App\Models\Expense;
|
use App\Models\Expense;
|
||||||
use App\Utils\Traits\GeneratesCounter;
|
use App\Utils\Traits\GeneratesCounter;
|
||||||
use Illuminate\Support\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
|
use Illuminate\Database\QueryException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ExpenseRepository.
|
* ExpenseRepository.
|
||||||
@ -24,6 +26,8 @@ class ExpenseRepository extends BaseRepository
|
|||||||
{
|
{
|
||||||
use GeneratesCounter;
|
use GeneratesCounter;
|
||||||
|
|
||||||
|
private $completed = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves the expense and its contacts.
|
* Saves the expense and its contacts.
|
||||||
*
|
*
|
||||||
@ -32,15 +36,17 @@ class ExpenseRepository extends BaseRepository
|
|||||||
*
|
*
|
||||||
* @return \App\Models\Expense|null expense Object
|
* @return \App\Models\Expense|null expense Object
|
||||||
*/
|
*/
|
||||||
public function save(array $data, Expense $expense) : ?Expense
|
public function save(array $data, Expense $expense): ?Expense
|
||||||
{
|
{
|
||||||
$expense->fill($data);
|
$expense->fill($data);
|
||||||
|
|
||||||
if (! $expense->id) {
|
if (!$expense->id) {
|
||||||
$expense = $this->processExchangeRates($data, $expense);
|
$expense = $this->processExchangeRates($data, $expense);
|
||||||
}
|
}
|
||||||
|
|
||||||
$expense->number = empty($expense->number) ? $this->getNextExpenseNumber($expense) : $expense->number;
|
if (empty($expense->number))
|
||||||
|
$expense = $this->findAndSaveNumber($expense);
|
||||||
|
|
||||||
$expense->save();
|
$expense->save();
|
||||||
|
|
||||||
if (array_key_exists('documents', $data)) {
|
if (array_key_exists('documents', $data)) {
|
||||||
@ -54,6 +60,7 @@ class ExpenseRepository extends BaseRepository
|
|||||||
* Store expenses in bulk.
|
* Store expenses in bulk.
|
||||||
*
|
*
|
||||||
* @param array $expense
|
* @param array $expense
|
||||||
|
*
|
||||||
* @return \App\Models\Expense|null
|
* @return \App\Models\Expense|null
|
||||||
*/
|
*/
|
||||||
public function create($expense): ?Expense
|
public function create($expense): ?Expense
|
||||||
@ -64,7 +71,7 @@ class ExpenseRepository extends BaseRepository
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function processExchangeRates($data, $expense)
|
public function processExchangeRates($data, $expense): Expense
|
||||||
{
|
{
|
||||||
if (array_key_exists('exchange_rate', $data) && isset($data['exchange_rate']) && $data['exchange_rate'] != 1) {
|
if (array_key_exists('exchange_rate', $data) && isset($data['exchange_rate']) && $data['exchange_rate'] != 1) {
|
||||||
return $expense;
|
return $expense;
|
||||||
@ -83,4 +90,35 @@ class ExpenseRepository extends BaseRepository
|
|||||||
|
|
||||||
return $expense;
|
return $expense;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle race conditions when creating expense numbers
|
||||||
|
*
|
||||||
|
* @param Expense $expense
|
||||||
|
* @return \App\Models\Expense
|
||||||
|
*/
|
||||||
|
private function findAndSaveNumber($expense): Expense
|
||||||
|
{
|
||||||
|
|
||||||
|
$x = 1;
|
||||||
|
|
||||||
|
do {
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
$expense->number = $this->getNextExpenseNumber($expense);
|
||||||
|
$expense->saveQuietly();
|
||||||
|
|
||||||
|
$this->completed = false;
|
||||||
|
} catch (QueryException $e) {
|
||||||
|
|
||||||
|
$x++;
|
||||||
|
|
||||||
|
if ($x > 50)
|
||||||
|
$this->completed = false;
|
||||||
|
}
|
||||||
|
} while ($this->completed);
|
||||||
|
|
||||||
|
return $expense;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,6 @@ class InvoiceRepository extends BaseRepository
|
|||||||
return $invoice;
|
return $invoice;
|
||||||
}
|
}
|
||||||
|
|
||||||
// $invoice->service()->markDeleted()->handleCancellation()->save();
|
|
||||||
$invoice = $invoice->service()->markDeleted()->save();
|
$invoice = $invoice->service()->markDeleted()->save();
|
||||||
|
|
||||||
parent::delete($invoice);
|
parent::delete($invoice);
|
||||||
|
@ -144,7 +144,7 @@ class PaymentRepository extends BaseRepository {
|
|||||||
|
|
||||||
$invoice_totals = array_sum(array_column($data['invoices'], 'amount'));
|
$invoice_totals = array_sum(array_column($data['invoices'], 'amount'));
|
||||||
|
|
||||||
$invoices = Invoice::whereIn('id', array_column($data['invoices'], 'invoice_id'))->get();
|
$invoices = Invoice::withTrashed()->whereIn('id', array_column($data['invoices'], 'invoice_id'))->get();
|
||||||
|
|
||||||
$payment->invoices()->saveMany($invoices);
|
$payment->invoices()->saveMany($invoices);
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ namespace App\Repositories;
|
|||||||
use App\Factory\TaskFactory;
|
use App\Factory\TaskFactory;
|
||||||
use App\Models\Task;
|
use App\Models\Task;
|
||||||
use App\Utils\Traits\GeneratesCounter;
|
use App\Utils\Traits\GeneratesCounter;
|
||||||
|
use Illuminate\Database\QueryException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TaskRepository.
|
* TaskRepository.
|
||||||
@ -24,6 +25,8 @@ class TaskRepository extends BaseRepository
|
|||||||
|
|
||||||
public $new_task = true;
|
public $new_task = true;
|
||||||
|
|
||||||
|
private $completed = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves the task and its contacts.
|
* Saves the task and its contacts.
|
||||||
*
|
*
|
||||||
@ -45,7 +48,7 @@ class TaskRepository extends BaseRepository
|
|||||||
$this->setDefaultStatus($task);
|
$this->setDefaultStatus($task);
|
||||||
}
|
}
|
||||||
|
|
||||||
$task->number = empty($task->number) || ! array_key_exists('number', $data) ? $this->getNextTaskNumber($task) : $data['number'];
|
$task->number = empty($task->number) || ! array_key_exists('number', $data) ? $this->trySaving($task) : $data['number'];
|
||||||
|
|
||||||
if (isset($data['description'])) {
|
if (isset($data['description'])) {
|
||||||
$task->description = trim($data['description']);
|
$task->description = trim($data['description']);
|
||||||
@ -244,4 +247,34 @@ class TaskRepository extends BaseRepository
|
|||||||
|
|
||||||
return $task;
|
return $task;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function trySaving(Task $task)
|
||||||
|
{
|
||||||
|
|
||||||
|
$x=1;
|
||||||
|
|
||||||
|
do{
|
||||||
|
|
||||||
|
try{
|
||||||
|
|
||||||
|
$task->number = $this->getNextTaskNumber($task);
|
||||||
|
$task->saveQuietly();
|
||||||
|
$this->completed = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
catch(QueryException $e){
|
||||||
|
|
||||||
|
$x++;
|
||||||
|
|
||||||
|
if($x>50)
|
||||||
|
$this->completed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
while($this->completed);
|
||||||
|
|
||||||
|
return $task->number;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ class ClientService
|
|||||||
|
|
||||||
\DB::connection(config('database.default'))->transaction(function () use($amount) {
|
\DB::connection(config('database.default'))->transaction(function () use($amount) {
|
||||||
|
|
||||||
$this->client = Client::where('id', $this->client->id)->lockForUpdate()->first();
|
$this->client = Client::withTrashed()->where('id', $this->client->id)->lockForUpdate()->first();
|
||||||
$this->client->balance += $amount;
|
$this->client->balance += $amount;
|
||||||
$this->client->save();
|
$this->client->save();
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ class ClientService
|
|||||||
|
|
||||||
\DB::connection(config('database.default'))->transaction(function () use($balance, $paid_to_date) {
|
\DB::connection(config('database.default'))->transaction(function () use($balance, $paid_to_date) {
|
||||||
|
|
||||||
$this->client = Client::where('id', $this->client->id)->lockForUpdate()->first();
|
$this->client = Client::withTrashed()->where('id', $this->client->id)->lockForUpdate()->first();
|
||||||
$this->client->balance += $balance;
|
$this->client->balance += $balance;
|
||||||
$this->client->paid_to_date += $paid_to_date;
|
$this->client->paid_to_date += $paid_to_date;
|
||||||
$this->client->save();
|
$this->client->save();
|
||||||
@ -65,7 +65,7 @@ class ClientService
|
|||||||
|
|
||||||
\DB::connection(config('database.default'))->transaction(function () use($amount) {
|
\DB::connection(config('database.default'))->transaction(function () use($amount) {
|
||||||
|
|
||||||
$this->client = Client::where('id', $this->client->id)->lockForUpdate()->first();
|
$this->client = Client::withTrashed()->where('id', $this->client->id)->lockForUpdate()->first();
|
||||||
$this->client->paid_to_date += $amount;
|
$this->client->paid_to_date += $amount;
|
||||||
$this->client->save();
|
$this->client->save();
|
||||||
|
|
||||||
@ -83,7 +83,7 @@ class ClientService
|
|||||||
|
|
||||||
public function getCreditBalance() :float
|
public function getCreditBalance() :float
|
||||||
{
|
{
|
||||||
$credits = Credit::where('client_id', $this->client->id)
|
$credits = Credit::withTrashed()->where('client_id', $this->client->id)
|
||||||
->where('is_deleted', false)
|
->where('is_deleted', false)
|
||||||
->where('balance', '>', 0)
|
->where('balance', '>', 0)
|
||||||
->where(function ($query) {
|
->where(function ($query) {
|
||||||
|
@ -70,7 +70,6 @@ class ApplyNumber extends AbstractService
|
|||||||
$this->invoice->saveQuietly();
|
$this->invoice->saveQuietly();
|
||||||
|
|
||||||
$this->completed = false;
|
$this->completed = false;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
catch(QueryException $e){
|
catch(QueryException $e){
|
||||||
@ -84,5 +83,8 @@ class ApplyNumber extends AbstractService
|
|||||||
}
|
}
|
||||||
while($this->completed);
|
while($this->completed);
|
||||||
|
|
||||||
|
|
||||||
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ class MarkPaid extends AbstractService
|
|||||||
|
|
||||||
\DB::connection(config('database.default'))->transaction(function () {
|
\DB::connection(config('database.default'))->transaction(function () {
|
||||||
|
|
||||||
$this->invoice = Invoice::where('id', $this->invoice->id)->lockForUpdate()->first();
|
$this->invoice = Invoice::withTrashed()->where('id', $this->invoice->id)->lockForUpdate()->first();
|
||||||
|
|
||||||
$this->payable_balance = $this->invoice->balance;
|
$this->payable_balance = $this->invoice->balance;
|
||||||
|
|
||||||
|
@ -44,6 +44,10 @@ class TriggeredActions extends AbstractService
|
|||||||
$this->invoice = $this->invoice->service()->markPaid()->save();
|
$this->invoice = $this->invoice->service()->markPaid()->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->request->has('mark_sent') && $this->request->input('mark_sent') == 'true') {
|
||||||
|
$this->invoice = $this->invoice->service()->markSent()->save();
|
||||||
|
}
|
||||||
|
|
||||||
if ($this->request->has('amount_paid') && is_numeric($this->request->input('amount_paid'))) {
|
if ($this->request->has('amount_paid') && is_numeric($this->request->input('amount_paid'))) {
|
||||||
$this->invoice = $this->invoice->service()->applyPaymentAmount($this->request->input('amount_paid'))->save();
|
$this->invoice = $this->invoice->service()->applyPaymentAmount($this->request->input('amount_paid'))->save();
|
||||||
}
|
}
|
||||||
@ -53,10 +57,6 @@ class TriggeredActions extends AbstractService
|
|||||||
$this->sendEmail();
|
$this->sendEmail();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->request->has('mark_sent') && $this->request->input('mark_sent') == 'true') {
|
|
||||||
$this->invoice = $this->invoice->service()->markSent()->save();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->request->has('cancel') && $this->request->input('cancel') == 'true') {
|
if ($this->request->has('cancel') && $this->request->input('cancel') == 'true') {
|
||||||
$this->invoice = $this->invoice->service()->handleCancellation()->save();
|
$this->invoice = $this->invoice->service()->handleCancellation()->save();
|
||||||
}
|
}
|
||||||
|
@ -109,6 +109,8 @@ class RecurringService
|
|||||||
|
|
||||||
if ($request->has('send_now') && $request->input('send_now') == 'true' && $this->recurring_entity->invoices()->count() == 0) {
|
if ($request->has('send_now') && $request->input('send_now') == 'true' && $this->recurring_entity->invoices()->count() == 0) {
|
||||||
$this->sendNow();
|
$this->sendNow();
|
||||||
|
|
||||||
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isset($this->recurring_entity->client))
|
if(isset($this->recurring_entity->client))
|
||||||
@ -125,10 +127,12 @@ class RecurringService
|
|||||||
|
|
||||||
if($this->recurring_entity instanceof RecurringInvoice && $this->recurring_entity->status_id == RecurringInvoice::STATUS_DRAFT){
|
if($this->recurring_entity instanceof RecurringInvoice && $this->recurring_entity->status_id == RecurringInvoice::STATUS_DRAFT){
|
||||||
$this->start()->save();
|
$this->start()->save();
|
||||||
SendRecurring::dispatch($this->recurring_entity, $this->recurring_entity->company->db);
|
SendRecurring::dispatchSync($this->recurring_entity, $this->recurring_entity->company->db);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->recurring_entity;
|
$this->recurring_entity = $this->recurring_entity->fresh();
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,6 +185,7 @@ class CompanyTransformer extends EntityTransformer
|
|||||||
'enable_applying_payments' => (bool) $company->enable_applying_payments,
|
'enable_applying_payments' => (bool) $company->enable_applying_payments,
|
||||||
'enabled_expense_tax_rates' => (int) $company->enabled_expense_tax_rates,
|
'enabled_expense_tax_rates' => (int) $company->enabled_expense_tax_rates,
|
||||||
'invoice_task_project' => (bool) $company->invoice_task_project,
|
'invoice_task_project' => (bool) $company->invoice_task_project,
|
||||||
|
'report_include_deleted' => (bool) $company->report_include_deleted,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,6 +114,22 @@ class Helpers
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 04-10-2022 Return Early if no reserved keywords are present, this is a very expenseive process
|
||||||
|
$string_hit = false;
|
||||||
|
|
||||||
|
foreach ( [':MONTH',':YEAR',':QUARTER',':WEEK'] as $string )
|
||||||
|
{
|
||||||
|
|
||||||
|
if(stripos($value, $string) !== FALSE) {
|
||||||
|
$string_hit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!$string_hit)
|
||||||
|
return $value;
|
||||||
|
// 04-10-2022 Return Early if no reserved keywords are present, this is a very expenseive process
|
||||||
|
|
||||||
Carbon::setLocale($entity->locale());
|
Carbon::setLocale($entity->locale());
|
||||||
|
|
||||||
$replacements = [
|
$replacements = [
|
||||||
|
@ -168,7 +168,7 @@ class HtmlEngine
|
|||||||
$data['$invoice.vendor'] = ['value' => $this->entity->vendor->present()->name(), 'label' => ctrans('texts.vendor_name')];
|
$data['$invoice.vendor'] = ['value' => $this->entity->vendor->present()->name(), 'label' => ctrans('texts.vendor_name')];
|
||||||
}
|
}
|
||||||
|
|
||||||
if(strlen($this->company->getSetting('qr_iban')) > 5 && strlen($this->company->getSetting('besr_id')) > 1)
|
if(strlen($this->company->getSetting('qr_iban')) > 5)
|
||||||
{
|
{
|
||||||
try{
|
try{
|
||||||
$data['$swiss_qr'] = ['value' => (new SwissQrGenerator($this->entity, $this->company))->run(), 'label' => ''];
|
$data['$swiss_qr'] = ['value' => (new SwissQrGenerator($this->entity, $this->company))->run(), 'label' => ''];
|
||||||
@ -522,6 +522,9 @@ class HtmlEngine
|
|||||||
$data['$font_name'] = ['value' => Helpers::resolveFont($this->settings->primary_font)['name'], 'label' => ''];
|
$data['$font_name'] = ['value' => Helpers::resolveFont($this->settings->primary_font)['name'], 'label' => ''];
|
||||||
$data['$font_url'] = ['value' => Helpers::resolveFont($this->settings->primary_font)['url'], 'label' => ''];
|
$data['$font_url'] = ['value' => Helpers::resolveFont($this->settings->primary_font)['url'], 'label' => ''];
|
||||||
|
|
||||||
|
$data['$secondary_font_name'] = ['value' => Helpers::resolveFont($this->settings->secondary_font)['name'], 'label' => ''];
|
||||||
|
$data['$secondary_font_url'] = ['value' => Helpers::resolveFont($this->settings->secondary_font)['url'], 'label' => ''];
|
||||||
|
|
||||||
$data['$invoiceninja.whitelabel'] = ['value' => 'https://raw.githubusercontent.com/invoiceninja/invoiceninja/v5-develop/public/images/new_logo.png', 'label' => ''];
|
$data['$invoiceninja.whitelabel'] = ['value' => 'https://raw.githubusercontent.com/invoiceninja/invoiceninja/v5-develop/public/images/new_logo.png', 'label' => ''];
|
||||||
|
|
||||||
$data['$primary_color'] = ['value' => $this->settings->primary_color, 'label' => ''];
|
$data['$primary_color'] = ['value' => $this->settings->primary_color, 'label' => ''];
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoice Ninja (https://invoiceninja.com).
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
*
|
*
|
||||||
@ -87,16 +88,16 @@ class TemplateEngine
|
|||||||
{
|
{
|
||||||
|
|
||||||
return $this->setEntity()
|
return $this->setEntity()
|
||||||
->setSettingsObject()
|
->setSettingsObject()
|
||||||
->setTemplates()
|
->setTemplates()
|
||||||
->replaceValues()
|
->replaceValues()
|
||||||
->renderTemplate();
|
->renderTemplate();
|
||||||
}
|
}
|
||||||
|
|
||||||
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(Str::camel($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();
|
||||||
@ -107,11 +108,10 @@ class TemplateEngine
|
|||||||
|
|
||||||
private function setSettingsObject()
|
private function setSettingsObject()
|
||||||
{
|
{
|
||||||
if($this->entity == 'purchaseOrder' || $this->entity == 'purchase_order'){
|
if ($this->entity == 'purchaseOrder' || $this->entity == 'purchase_order') {
|
||||||
$this->settings_entity = auth()->user()->company();
|
$this->settings_entity = auth()->user()->company();
|
||||||
$this->settings = $this->settings_entity->settings;
|
$this->settings = $this->settings_entity->settings;
|
||||||
}
|
} elseif ($this->entity_obj->client()->exists()) {
|
||||||
elseif ($this->entity_obj->client()->exists()) {
|
|
||||||
$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 {
|
||||||
@ -155,13 +155,11 @@ 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 == 'purchaseOrder'){
|
if ($this->entity_obj->client()->exists()) {
|
||||||
$this->fakerValues();
|
|
||||||
}
|
|
||||||
elseif ($this->entity_obj->client()->exists()) {
|
|
||||||
$this->entityValues($this->entity_obj->client->primary_contact()->first());
|
$this->entityValues($this->entity_obj->client->primary_contact()->first());
|
||||||
}
|
} elseif ($this->entity_obj->vendor()->exists()) {
|
||||||
else {
|
$this->entityValues($this->entity_obj->vendor->primary_contact()->first());
|
||||||
|
} else {
|
||||||
$this->fakerValues();
|
$this->fakerValues();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,16 +182,16 @@ class TemplateEngine
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
$this->body = $converter->convert($this->body)->getContent();
|
$this->body = $converter->convert($this->body)->getContent();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function entityValues($contact)
|
private function entityValues($contact)
|
||||||
{
|
{
|
||||||
if($this->entity == 'purchaseOrder')
|
if (in_array($this->entity, ['purchaseOrder', 'purchase_order']))
|
||||||
$this->labels_and_values = (new VendorHtmlEngine($this->entity_obj->invitations->first()))->generateLabelsAndValues();
|
$this->labels_and_values = (new VendorHtmlEngine($this->entity_obj->invitations->first()))->generateLabelsAndValues();
|
||||||
else
|
else
|
||||||
$this->labels_and_values = (new HtmlEngine($this->entity_obj->invitations->first()))->generateLabelsAndValues();
|
$this->labels_and_values = (new HtmlEngine($this->entity_obj->invitations->first()))->generateLabelsAndValues();
|
||||||
|
|
||||||
|
|
||||||
$this->body = strtr($this->body, $this->labels_and_values['labels']);
|
$this->body = strtr($this->body, $this->labels_and_values['labels']);
|
||||||
$this->body = strtr($this->body, $this->labels_and_values['values']);
|
$this->body = strtr($this->body, $this->labels_and_values['values']);
|
||||||
|
|
||||||
@ -217,16 +215,15 @@ 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()->exists())
|
if ($this->entity_obj->client()->exists())
|
||||||
$data = array_merge($data, Helpers::sharedEmailVariables($this->entity_obj->client));
|
$data = array_merge($data, Helpers::sharedEmailVariables($this->entity_obj->client));
|
||||||
else{
|
else {
|
||||||
|
|
||||||
$data['signature'] = $this->settings->email_signature;
|
$data['signature'] = $this->settings->email_signature;
|
||||||
$data['settings'] = $this->settings;
|
$data['settings'] = $this->settings;
|
||||||
$data['whitelabel'] = $this->entity_obj ? $this->entity_obj->company->account->isPaid() : true;
|
$data['whitelabel'] = $this->entity_obj ? $this->entity_obj->company->account->isPaid() : true;
|
||||||
$data['company'] = $this->entity_obj ? $this->entity_obj->company : '';
|
$data['company'] = $this->entity_obj ? $this->entity_obj->company : '';
|
||||||
$data['settings'] = $this->settings;
|
$data['settings'] = $this->settings;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -235,7 +232,6 @@ class TemplateEngine
|
|||||||
|
|
||||||
// In order to parse variables such as $signature in the body,
|
// In order to parse variables such as $signature in the body,
|
||||||
// we need to replace strings with the values from HTMLEngine.
|
// we need to replace strings with the values from HTMLEngine.
|
||||||
|
|
||||||
$wrapper = strtr($wrapper, $this->labels_and_values['values']);
|
$wrapper = strtr($wrapper, $this->labels_and_values['values']);
|
||||||
|
|
||||||
/*If no custom design exists, send back a blank!*/
|
/*If no custom design exists, send back a blank!*/
|
||||||
@ -269,7 +265,7 @@ class TemplateEngine
|
|||||||
|
|
||||||
private function mockEntity()
|
private function mockEntity()
|
||||||
{
|
{
|
||||||
if(!$this->entity && $this->template && str_contains($this->template, 'purchase_order'))
|
if (!$this->entity && $this->template && str_contains($this->template, 'purchase_order'))
|
||||||
$this->entity = 'purchaseOrder';
|
$this->entity = 'purchaseOrder';
|
||||||
|
|
||||||
DB::connection(config('database.default'))->beginTransaction();
|
DB::connection(config('database.default'))->beginTransaction();
|
||||||
@ -289,7 +285,7 @@ class TemplateEngine
|
|||||||
'send_email' => true,
|
'send_email' => true,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (! $this->entity || $this->entity == 'invoice') {
|
if (!$this->entity || $this->entity == 'invoice') {
|
||||||
$this->entity_obj = Invoice::factory()->create([
|
$this->entity_obj = Invoice::factory()->create([
|
||||||
'user_id' => auth()->user()->id,
|
'user_id' => auth()->user()->id,
|
||||||
'company_id' => auth()->user()->company()->id,
|
'company_id' => auth()->user()->company()->id,
|
||||||
@ -321,40 +317,37 @@ class TemplateEngine
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
if($this->entity == 'purchaseOrder')
|
if ($this->entity == 'purchaseOrder') {
|
||||||
{
|
|
||||||
|
|
||||||
$vendor = Vendor::factory()->create([
|
$vendor = Vendor::factory()->create([
|
||||||
'user_id' => auth()->user()->id,
|
'user_id' => auth()->user()->id,
|
||||||
'company_id' => auth()->user()->company()->id,
|
'company_id' => auth()->user()->company()->id,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$contact = VendorContact::factory()->create([
|
$contact = VendorContact::factory()->create([
|
||||||
'user_id' => auth()->user()->id,
|
'user_id' => auth()->user()->id,
|
||||||
'company_id' => auth()->user()->company()->id,
|
'company_id' => auth()->user()->company()->id,
|
||||||
'vendor_id' => $vendor->id,
|
'vendor_id' => $vendor->id,
|
||||||
'is_primary' => 1,
|
'is_primary' => 1,
|
||||||
'send_email' => true,
|
'send_email' => true,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
||||||
$this->entity_obj = PurchaseOrder::factory()->create([
|
$this->entity_obj = PurchaseOrder::factory()->create([
|
||||||
'user_id' => auth()->user()->id,
|
'user_id' => auth()->user()->id,
|
||||||
'company_id' => auth()->user()->company()->id,
|
'company_id' => auth()->user()->company()->id,
|
||||||
'vendor_id' => $vendor->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,
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$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)
|
if ($vendor) {
|
||||||
{
|
|
||||||
|
|
||||||
$this->entity_obj->setRelation('invitations', $invitation);
|
$this->entity_obj->setRelation('invitations', $invitation);
|
||||||
$this->entity_obj->setRelation('vendor', $vendor);
|
$this->entity_obj->setRelation('vendor', $vendor);
|
||||||
@ -362,10 +355,7 @@ class TemplateEngine
|
|||||||
$this->entity_obj->load('vendor');
|
$this->entity_obj->load('vendor');
|
||||||
$vendor->setRelation('company', auth()->user()->company());
|
$vendor->setRelation('company', auth()->user()->company());
|
||||||
$vendor->load('company');
|
$vendor->load('company');
|
||||||
|
} else {
|
||||||
}
|
|
||||||
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());
|
||||||
|
@ -33,6 +33,9 @@ use Illuminate\Support\Str;
|
|||||||
*/
|
*/
|
||||||
trait GeneratesConvertedQuoteCounter
|
trait GeneratesConvertedQuoteCounter
|
||||||
{
|
{
|
||||||
|
|
||||||
|
private int $update_counter;
|
||||||
|
|
||||||
private function harvestQuoteCounter($quote, $invoice, Client $client)
|
private function harvestQuoteCounter($quote, $invoice, Client $client)
|
||||||
{
|
{
|
||||||
$settings = $client->getMergedSettings();
|
$settings = $client->getMergedSettings();
|
||||||
|
@ -34,6 +34,9 @@ use Illuminate\Support\Str;
|
|||||||
*/
|
*/
|
||||||
trait GeneratesCounter
|
trait GeneratesCounter
|
||||||
{
|
{
|
||||||
|
|
||||||
|
private int $update_counter;
|
||||||
|
|
||||||
//todo in the form validation, we need to ensure that if a prefix and pattern is set we throw a validation error,
|
//todo in the form validation, we need to ensure that if a prefix and pattern is set we throw a validation error,
|
||||||
//only one type is allow else this will cause confusion to the end user
|
//only one type is allow else this will cause confusion to the end user
|
||||||
|
|
||||||
@ -412,28 +415,36 @@ trait GeneratesCounter
|
|||||||
* @param string $prefix
|
* @param string $prefix
|
||||||
* @return string The padded and prefixed entity number
|
* @return string The padded and prefixed entity number
|
||||||
*/
|
*/
|
||||||
private function checkEntityNumber($class, $entity, $counter, $padding, $pattern, $prefix = '')
|
private function checkEntityNumber($class, $entity, $counter, $padding, $pattern, $prefix = '') :string
|
||||||
{
|
{
|
||||||
$check = false;
|
$check = false;
|
||||||
$check_counter = 1;
|
$check_counter = 1;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
|
||||||
$number = $this->padCounter($counter, $padding);
|
$number = $this->padCounter($counter, $padding);
|
||||||
|
|
||||||
$number = $this->applyNumberPattern($entity, $number, $pattern);
|
$number = $this->applyNumberPattern($entity, $number, $pattern);
|
||||||
|
|
||||||
$number = $this->prefixCounter($number, $prefix);
|
$number = $this->prefixCounter($number, $prefix);
|
||||||
|
|
||||||
$check = $class::whereCompanyId($entity->company_id)->whereNumber($number)->withTrashed()->exists();
|
$check = $class::where('company_id', $entity->company_id)->where('number', $number)->withTrashed()->exists();
|
||||||
|
|
||||||
$counter++;
|
$counter++;
|
||||||
$check_counter++;
|
$check_counter++;
|
||||||
|
|
||||||
if ($check_counter > 100) {
|
if ($check_counter > 100) {
|
||||||
|
|
||||||
|
$this->update_counter = $counter--;
|
||||||
|
|
||||||
return $number.'_'.Str::random(5);
|
return $number.'_'.Str::random(5);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} while ($check);
|
} while ($check);
|
||||||
|
|
||||||
|
$this->update_counter = $counter--;
|
||||||
|
|
||||||
return $number;
|
return $number;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -465,7 +476,8 @@ trait GeneratesCounter
|
|||||||
$settings->{$counter_name} = 1;
|
$settings->{$counter_name} = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
$settings->{$counter_name} = $settings->{$counter_name} + 1;
|
// $settings->{$counter_name} = $settings->{$counter_name} + 1;
|
||||||
|
$settings->{$counter_name} = $this->update_counter;
|
||||||
|
|
||||||
$entity->settings = $settings;
|
$entity->settings = $settings;
|
||||||
|
|
||||||
|
@ -264,7 +264,8 @@ trait MakesInvoiceValues
|
|||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function transformLineItems($items, $table_type = '$product') :array
|
public function transformLineItems($items, $table_type = '$product') :array
|
||||||
{
|
{ //$start = microtime(true);
|
||||||
|
|
||||||
$entity = $this->client ? $this->client : $this->company;
|
$entity = $this->client ? $this->client : $this->company;
|
||||||
|
|
||||||
$data = [];
|
$data = [];
|
||||||
@ -274,6 +275,8 @@ trait MakesInvoiceValues
|
|||||||
|
|
||||||
$locale_info = localeconv();
|
$locale_info = localeconv();
|
||||||
|
|
||||||
|
$entity_currency = $entity->currency();
|
||||||
|
|
||||||
foreach ($items as $key => $item) {
|
foreach ($items as $key => $item) {
|
||||||
if ($table_type == '$product' && $item->type_id != 1) {
|
if ($table_type == '$product' && $item->type_id != 1) {
|
||||||
if ($item->type_id != 4 && $item->type_id != 6 && $item->type_id != 5) {
|
if ($item->type_id != 4 && $item->type_id != 6 && $item->type_id != 5) {
|
||||||
@ -297,13 +300,13 @@ trait MakesInvoiceValues
|
|||||||
$data[$key][$table_type.'.notes'] = Helpers::processReservedKeywords($item->notes, $entity);
|
$data[$key][$table_type.'.notes'] = Helpers::processReservedKeywords($item->notes, $entity);
|
||||||
$data[$key][$table_type.'.description'] = Helpers::processReservedKeywords($item->notes, $entity);
|
$data[$key][$table_type.'.description'] = Helpers::processReservedKeywords($item->notes, $entity);
|
||||||
|
|
||||||
$data[$key][$table_type.".{$_table_type}1"] = $helpers->formatCustomFieldValue($this->company->custom_fields, "{$_table_type}1", $item->custom_value1, $entity);
|
$data[$key][$table_type.".{$_table_type}1"] = strlen($item->custom_value1) > 1 ? $helpers->formatCustomFieldValue($this->company->custom_fields, "{$_table_type}1", $item->custom_value1, $entity) : '';
|
||||||
$data[$key][$table_type.".{$_table_type}2"] = $helpers->formatCustomFieldValue($this->company->custom_fields, "{$_table_type}2", $item->custom_value2, $entity);
|
$data[$key][$table_type.".{$_table_type}2"] = strlen($item->custom_value1) > 2 ? $helpers->formatCustomFieldValue($this->company->custom_fields, "{$_table_type}2", $item->custom_value2, $entity) : '';
|
||||||
$data[$key][$table_type.".{$_table_type}3"] = $helpers->formatCustomFieldValue($this->company->custom_fields, "{$_table_type}3", $item->custom_value3, $entity);
|
$data[$key][$table_type.".{$_table_type}3"] = strlen($item->custom_value1) > 3 ? $helpers->formatCustomFieldValue($this->company->custom_fields, "{$_table_type}3", $item->custom_value3, $entity) : '';
|
||||||
$data[$key][$table_type.".{$_table_type}4"] = $helpers->formatCustomFieldValue($this->company->custom_fields, "{$_table_type}4", $item->custom_value4, $entity);
|
$data[$key][$table_type.".{$_table_type}4"] = strlen($item->custom_value1) > 4 ? $helpers->formatCustomFieldValue($this->company->custom_fields, "{$_table_type}4", $item->custom_value4, $entity) : '';
|
||||||
|
|
||||||
if ($item->quantity > 0 || $item->cost > 0) {
|
if ($item->quantity > 0 || $item->cost > 0) {
|
||||||
$data[$key][$table_type.'.quantity'] = Number::formatValueNoTrailingZeroes($item->quantity, $entity->currency());
|
$data[$key][$table_type.'.quantity'] = Number::formatValueNoTrailingZeroes($item->quantity, $entity_currency);
|
||||||
|
|
||||||
$data[$key][$table_type.'.unit_cost'] = Number::formatMoneyNoRounding($item->cost, $entity);
|
$data[$key][$table_type.'.unit_cost'] = Number::formatMoneyNoRounding($item->cost, $entity);
|
||||||
|
|
||||||
@ -357,6 +360,8 @@ trait MakesInvoiceValues
|
|||||||
$data[$key]['task_id'] = property_exists($item, 'task_id') ? $item->task_id : '';
|
$data[$key]['task_id'] = property_exists($item, 'task_id') ? $item->task_id : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//nlog(microtime(true) - $start);
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,6 +29,11 @@ use Exception;
|
|||||||
use Illuminate\Support\Facades\App;
|
use Illuminate\Support\Facades\App;
|
||||||
use Illuminate\Support\Facades\Cache;
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note the premise used here is that any currencies will be formatted back to the company currency and not
|
||||||
|
* user the vendor currency, if we continue to extend on vendor, we will need to relook at this
|
||||||
|
*/
|
||||||
|
|
||||||
class VendorHtmlEngine
|
class VendorHtmlEngine
|
||||||
{
|
{
|
||||||
use MakesDates;
|
use MakesDates;
|
||||||
@ -164,16 +169,16 @@ class VendorHtmlEngine
|
|||||||
|
|
||||||
$data['$entity_number'] = &$data['$number'];
|
$data['$entity_number'] = &$data['$number'];
|
||||||
$data['$discount'] = ['value' => $this->entity->discount, 'label' => ctrans('texts.discount')];
|
$data['$discount'] = ['value' => $this->entity->discount, 'label' => ctrans('texts.discount')];
|
||||||
$data['$subtotal'] = ['value' => Number::formatMoney($this->entity_calc->getSubTotal(), $this->vendor) ?: ' ', 'label' => ctrans('texts.subtotal')];
|
$data['$subtotal'] = ['value' => Number::formatMoney($this->entity_calc->getSubTotal(), $this->company) ?: ' ', 'label' => ctrans('texts.subtotal')];
|
||||||
$data['$gross_subtotal'] = ['value' => Number::formatMoney($this->entity_calc->getGrossSubTotal(), $this->vendor) ?: ' ', 'label' => ctrans('texts.subtotal')];
|
$data['$gross_subtotal'] = ['value' => Number::formatMoney($this->entity_calc->getGrossSubTotal(), $this->company) ?: ' ', 'label' => ctrans('texts.subtotal')];
|
||||||
|
|
||||||
if($this->entity->uses_inclusive_taxes)
|
if($this->entity->uses_inclusive_taxes)
|
||||||
$data['$net_subtotal'] = ['value' => Number::formatMoney(($this->entity_calc->getSubTotal() - $this->entity->total_taxes - $this->entity_calc->getTotalDiscount()), $this->vendor) ?: ' ', 'label' => ctrans('texts.net_subtotal')];
|
$data['$net_subtotal'] = ['value' => Number::formatMoney(($this->entity_calc->getSubTotal() - $this->entity->total_taxes - $this->entity_calc->getTotalDiscount()), $this->company) ?: ' ', 'label' => ctrans('texts.net_subtotal')];
|
||||||
else
|
else
|
||||||
$data['$net_subtotal'] = ['value' => Number::formatMoney($this->entity_calc->getSubTotal() - $this->entity_calc->getTotalDiscount(), $this->vendor) ?: ' ', 'label' => ctrans('texts.net_subtotal')];
|
$data['$net_subtotal'] = ['value' => Number::formatMoney($this->entity_calc->getSubTotal() - $this->entity_calc->getTotalDiscount(), $this->company) ?: ' ', 'label' => ctrans('texts.net_subtotal')];
|
||||||
|
|
||||||
if ($this->entity->partial > 0) {
|
if ($this->entity->partial > 0) {
|
||||||
$data['$balance_due'] = ['value' => Number::formatMoney($this->entity->partial, $this->vendor) ?: ' ', 'label' => ctrans('texts.partial_due')];
|
$data['$balance_due'] = ['value' => Number::formatMoney($this->entity->partial, $this->company) ?: ' ', 'label' => ctrans('texts.partial_due')];
|
||||||
$data['$balance_due_raw'] = ['value' => $this->entity->partial, 'label' => ctrans('texts.partial_due')];
|
$data['$balance_due_raw'] = ['value' => $this->entity->partial, 'label' => ctrans('texts.partial_due')];
|
||||||
$data['$amount_raw'] = ['value' => $this->entity->partial, 'label' => ctrans('texts.partial_due')];
|
$data['$amount_raw'] = ['value' => $this->entity->partial, 'label' => ctrans('texts.partial_due')];
|
||||||
$data['$due_date'] = ['value' => $this->translateDate($this->entity->partial_due_date, $this->company->date_format(), $this->company->locale()) ?: ' ', 'label' => ctrans('texts.'.$this->entity_string.'_due_date')];
|
$data['$due_date'] = ['value' => $this->translateDate($this->entity->partial_due_date, $this->company->date_format(), $this->company->locale()) ?: ' ', 'label' => ctrans('texts.'.$this->entity_string.'_due_date')];
|
||||||
@ -181,12 +186,12 @@ class VendorHtmlEngine
|
|||||||
} else {
|
} else {
|
||||||
|
|
||||||
if($this->entity->status_id == 1){
|
if($this->entity->status_id == 1){
|
||||||
$data['$balance_due'] = ['value' => Number::formatMoney($this->entity->amount, $this->vendor) ?: ' ', 'label' => ctrans('texts.balance_due')];
|
$data['$balance_due'] = ['value' => Number::formatMoney($this->entity->amount, $this->company) ?: ' ', 'label' => ctrans('texts.balance_due')];
|
||||||
$data['$balance_due_raw'] = ['value' => $this->entity->amount, 'label' => ctrans('texts.balance_due')];
|
$data['$balance_due_raw'] = ['value' => $this->entity->amount, 'label' => ctrans('texts.balance_due')];
|
||||||
$data['$amount_raw'] = ['value' => $this->entity->amount, 'label' => ctrans('texts.amount')];
|
$data['$amount_raw'] = ['value' => $this->entity->amount, 'label' => ctrans('texts.amount')];
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
$data['$balance_due'] = ['value' => Number::formatMoney($this->entity->balance, $this->vendor) ?: ' ', 'label' => ctrans('texts.balance_due')];
|
$data['$balance_due'] = ['value' => Number::formatMoney($this->entity->balance, $this->company) ?: ' ', 'label' => ctrans('texts.balance_due')];
|
||||||
$data['$balance_due_raw'] = ['value' => $this->entity->balance, 'label' => ctrans('texts.balance_due')];
|
$data['$balance_due_raw'] = ['value' => $this->entity->balance, 'label' => ctrans('texts.balance_due')];
|
||||||
$data['$amount_raw'] = ['value' => $this->entity->amount, 'label' => ctrans('texts.amount')];
|
$data['$amount_raw'] = ['value' => $this->entity->amount, 'label' => ctrans('texts.amount')];
|
||||||
}
|
}
|
||||||
@ -194,18 +199,18 @@ class VendorHtmlEngine
|
|||||||
|
|
||||||
// $data['$balance_due'] = $data['$balance_due'];
|
// $data['$balance_due'] = $data['$balance_due'];
|
||||||
$data['$outstanding'] = &$data['$balance_due'];
|
$data['$outstanding'] = &$data['$balance_due'];
|
||||||
$data['$partial_due'] = ['value' => Number::formatMoney($this->entity->partial, $this->vendor) ?: ' ', 'label' => ctrans('texts.partial_due')];
|
$data['$partial_due'] = ['value' => Number::formatMoney($this->entity->partial, $this->company) ?: ' ', 'label' => ctrans('texts.partial_due')];
|
||||||
$data['$partial'] = &$data['$partial_due'];
|
$data['$partial'] = &$data['$partial_due'];
|
||||||
|
|
||||||
$data['$total'] = ['value' => Number::formatMoney($this->entity_calc->getTotal(), $this->vendor) ?: ' ', 'label' => ctrans('texts.total')];
|
$data['$total'] = ['value' => Number::formatMoney($this->entity_calc->getTotal(), $this->company) ?: ' ', 'label' => ctrans('texts.total')];
|
||||||
|
|
||||||
$data['$purchase_order.total'] = &$data['$total'];
|
$data['$purchase_order.total'] = &$data['$total'];
|
||||||
|
|
||||||
$data['$amount'] = &$data['$total'];
|
$data['$amount'] = &$data['$total'];
|
||||||
$data['$amount_due'] = ['value' => &$data['$total']['value'], 'label' => ctrans('texts.amount_due')];
|
$data['$amount_due'] = ['value' => &$data['$total']['value'], 'label' => ctrans('texts.amount_due')];
|
||||||
$data['$balance'] = ['value' => Number::formatMoney($this->entity_calc->getBalance(), $this->vendor) ?: ' ', 'label' => ctrans('texts.balance')];
|
$data['$balance'] = ['value' => Number::formatMoney($this->entity_calc->getBalance(), $this->company) ?: ' ', 'label' => ctrans('texts.balance')];
|
||||||
|
|
||||||
$data['$taxes'] = ['value' => Number::formatMoney($this->entity_calc->getItemTotalTaxes(), $this->vendor) ?: ' ', 'label' => ctrans('texts.taxes')];
|
$data['$taxes'] = ['value' => Number::formatMoney($this->entity_calc->getItemTotalTaxes(), $this->company) ?: ' ', 'label' => ctrans('texts.taxes')];
|
||||||
|
|
||||||
$data['$user.name'] = ['value' => $this->entity->user->present()->name(), 'label' => ctrans('texts.name')];
|
$data['$user.name'] = ['value' => $this->entity->user->present()->name(), 'label' => ctrans('texts.name')];
|
||||||
$data['$user.first_name'] = ['value' => $this->entity->user->first_name, 'label' => ctrans('texts.first_name')];
|
$data['$user.first_name'] = ['value' => $this->entity->user->first_name, 'label' => ctrans('texts.first_name')];
|
||||||
@ -277,7 +282,7 @@ class VendorHtmlEngine
|
|||||||
|
|
||||||
$data['$vendor.currency'] = ['value' => $this->vendor->currency()->code, 'label' => ''];
|
$data['$vendor.currency'] = ['value' => $this->vendor->currency()->code, 'label' => ''];
|
||||||
|
|
||||||
$data['$paid_to_date'] = ['value' => Number::formatMoney($this->entity->paid_to_date, $this->vendor), 'label' => ctrans('texts.paid_to_date')];
|
$data['$paid_to_date'] = ['value' => Number::formatMoney($this->entity->paid_to_date, $this->company), 'label' => ctrans('texts.paid_to_date')];
|
||||||
|
|
||||||
$data['$contact.full_name'] = ['value' => $this->contact->present()->name(), 'label' => ctrans('texts.name')];
|
$data['$contact.full_name'] = ['value' => $this->contact->present()->name(), 'label' => ctrans('texts.name')];
|
||||||
$data['$contact'] = &$data['$contact.full_name'];
|
$data['$contact'] = &$data['$contact.full_name'];
|
||||||
@ -332,10 +337,10 @@ class VendorHtmlEngine
|
|||||||
$data['$company.custom3'] = &$data['$company3'];
|
$data['$company.custom3'] = &$data['$company3'];
|
||||||
$data['$company.custom4'] = &$data['$company4'];
|
$data['$company.custom4'] = &$data['$company4'];
|
||||||
|
|
||||||
$data['$custom_surcharge1'] = ['value' => Number::formatMoney($this->entity->custom_surcharge1, $this->vendor) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'surcharge1')];
|
$data['$custom_surcharge1'] = ['value' => Number::formatMoney($this->entity->custom_surcharge1, $this->company) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'surcharge1')];
|
||||||
$data['$custom_surcharge2'] = ['value' => Number::formatMoney($this->entity->custom_surcharge2, $this->vendor) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'surcharge2')];
|
$data['$custom_surcharge2'] = ['value' => Number::formatMoney($this->entity->custom_surcharge2, $this->company) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'surcharge2')];
|
||||||
$data['$custom_surcharge3'] = ['value' => Number::formatMoney($this->entity->custom_surcharge3, $this->vendor) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'surcharge3')];
|
$data['$custom_surcharge3'] = ['value' => Number::formatMoney($this->entity->custom_surcharge3, $this->company) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'surcharge3')];
|
||||||
$data['$custom_surcharge4'] = ['value' => Number::formatMoney($this->entity->custom_surcharge4, $this->vendor) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'surcharge4')];
|
$data['$custom_surcharge4'] = ['value' => Number::formatMoney($this->entity->custom_surcharge4, $this->company) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'surcharge4')];
|
||||||
|
|
||||||
$data['$product.item'] = ['value' => '', 'label' => ctrans('texts.item')];
|
$data['$product.item'] = ['value' => '', 'label' => ctrans('texts.item')];
|
||||||
$data['$product.date'] = ['value' => '', 'label' => ctrans('texts.date')];
|
$data['$product.date'] = ['value' => '', 'label' => ctrans('texts.date')];
|
||||||
@ -608,7 +613,7 @@ class VendorHtmlEngine
|
|||||||
foreach ($tax_map as $tax) {
|
foreach ($tax_map as $tax) {
|
||||||
$data .= '<tr class="line_taxes">';
|
$data .= '<tr class="line_taxes">';
|
||||||
$data .= '<td>'.$tax['name'].'</td>';
|
$data .= '<td>'.$tax['name'].'</td>';
|
||||||
$data .= '<td>'.Number::formatMoney($tax['total'], $this->vendor).'</td></tr>';
|
$data .= '<td>'.Number::formatMoney($tax['total'], $this->company).'</td></tr>';
|
||||||
}
|
}
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
@ -621,7 +626,7 @@ class VendorHtmlEngine
|
|||||||
$data = '';
|
$data = '';
|
||||||
|
|
||||||
foreach ($tax_map as $tax) {
|
foreach ($tax_map as $tax) {
|
||||||
$data .= '<span>'.Number::formatMoney($tax['total'], $this->vendor).'</span>';
|
$data .= '<span>'.Number::formatMoney($tax['total'], $this->company).'</span>';
|
||||||
}
|
}
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
@ -639,7 +644,7 @@ class VendorHtmlEngine
|
|||||||
$data .= '<tr>';
|
$data .= '<tr>';
|
||||||
$data .= '<td colspan="{ count($this->entity->company->settings->pdf_variables->total_columns) - 2 }"></td>';
|
$data .= '<td colspan="{ count($this->entity->company->settings->pdf_variables->total_columns) - 2 }"></td>';
|
||||||
$data .= '<td>'.$tax['name'].'</td>';
|
$data .= '<td>'.$tax['name'].'</td>';
|
||||||
$data .= '<td>'.Number::formatMoney($tax['total'], $this->vendor).'</td></tr>';
|
$data .= '<td>'.Number::formatMoney($tax['total'], $this->company).'</td></tr>';
|
||||||
}
|
}
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
|
@ -40,7 +40,7 @@
|
|||||||
"authorizenet/authorizenet": "^2.0",
|
"authorizenet/authorizenet": "^2.0",
|
||||||
"awobaz/compoships": "^2.1",
|
"awobaz/compoships": "^2.1",
|
||||||
"bacon/bacon-qr-code": "^2.0",
|
"bacon/bacon-qr-code": "^2.0",
|
||||||
"beganovich/snappdf": "^2",
|
"beganovich/snappdf": "^3",
|
||||||
"braintree/braintree_php": "^6.0",
|
"braintree/braintree_php": "^6.0",
|
||||||
"checkout/checkout-sdk-php": "^2.5",
|
"checkout/checkout-sdk-php": "^2.5",
|
||||||
"cleverit/ubl_invoice": "^1.3",
|
"cleverit/ubl_invoice": "^1.3",
|
||||||
@ -57,7 +57,7 @@
|
|||||||
"intervention/image": "^2.5",
|
"intervention/image": "^2.5",
|
||||||
"invoiceninja/inspector": "^1.0",
|
"invoiceninja/inspector": "^1.0",
|
||||||
"laracasts/presenter": "^0.2.1",
|
"laracasts/presenter": "^0.2.1",
|
||||||
"laravel/framework": "^9.17",
|
"laravel/framework": "^9.3",
|
||||||
"laravel/slack-notification-channel": "^2.2",
|
"laravel/slack-notification-channel": "^2.2",
|
||||||
"laravel/socialite": "^5",
|
"laravel/socialite": "^5",
|
||||||
"laravel/tinker": "^2.7",
|
"laravel/tinker": "^2.7",
|
||||||
@ -88,7 +88,7 @@
|
|||||||
"symfony/mailgun-mailer": "^6.1",
|
"symfony/mailgun-mailer": "^6.1",
|
||||||
"symfony/postmark-mailer": "^6.1",
|
"symfony/postmark-mailer": "^6.1",
|
||||||
"tijsverkoyen/css-to-inline-styles": "^2.2",
|
"tijsverkoyen/css-to-inline-styles": "^2.2",
|
||||||
"turbo124/beacon": "^1.2",
|
"turbo124/beacon": "^1.3",
|
||||||
"twilio/sdk": "^6.40",
|
"twilio/sdk": "^6.40",
|
||||||
"webpatser/laravel-countries": "dev-master#75992ad",
|
"webpatser/laravel-countries": "dev-master#75992ad",
|
||||||
"wepay/php-sdk": "^0.3"
|
"wepay/php-sdk": "^0.3"
|
||||||
|
468
composer.lock
generated
468
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -14,8 +14,8 @@ return [
|
|||||||
'require_https' => env('REQUIRE_HTTPS', true),
|
'require_https' => env('REQUIRE_HTTPS', true),
|
||||||
'app_url' => rtrim(env('APP_URL', ''), '/'),
|
'app_url' => rtrim(env('APP_URL', ''), '/'),
|
||||||
'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
|
'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
|
||||||
'app_version' => '5.5.19',
|
'app_version' => '5.5.25',
|
||||||
'app_tag' => '5.5.19',
|
'app_tag' => '5.5.25',
|
||||||
'minimum_client_version' => '5.0.16',
|
'minimum_client_version' => '5.0.16',
|
||||||
'terms_version' => '1.0.1',
|
'terms_version' => '1.0.1',
|
||||||
'api_secret' => env('API_SECRET', ''),
|
'api_secret' => env('API_SECRET', ''),
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use App\Listeners\Subscription\AppStoreRenewSubscription;
|
||||||
use Imdhemy\Purchases\Events\AppStore\Cancel;
|
use Imdhemy\Purchases\Events\AppStore\Cancel;
|
||||||
use Imdhemy\Purchases\Events\AppStore\DidChangeRenewalPref;
|
use Imdhemy\Purchases\Events\AppStore\DidChangeRenewalPref;
|
||||||
use Imdhemy\Purchases\Events\AppStore\DidChangeRenewalStatus;
|
use Imdhemy\Purchases\Events\AppStore\DidChangeRenewalStatus;
|
||||||
@ -16,8 +17,8 @@ use Imdhemy\Purchases\Events\GooglePlay\SubscriptionDeferred;
|
|||||||
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionExpired;
|
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionExpired;
|
||||||
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionInGracePeriod;
|
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionInGracePeriod;
|
||||||
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionOnHold;
|
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionOnHold;
|
||||||
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionPaused;
|
|
||||||
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionPauseScheduleChanged;
|
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionPauseScheduleChanged;
|
||||||
|
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionPaused;
|
||||||
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionPriceChangeConfirmed;
|
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionPriceChangeConfirmed;
|
||||||
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionPurchased;
|
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionPurchased;
|
||||||
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionRecovered;
|
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionRecovered;
|
||||||
@ -62,7 +63,7 @@ return [
|
|||||||
DidChangeRenewalStatus::class => [],
|
DidChangeRenewalStatus::class => [],
|
||||||
DidFailToRenew::class => [],
|
DidFailToRenew::class => [],
|
||||||
DidRecover::class => [],
|
DidRecover::class => [],
|
||||||
DidRenew::class => [],
|
DidRenew::class => [AppStoreRenewSubscription::class],
|
||||||
InitialBuy::class => [],
|
InitialBuy::class => [],
|
||||||
InteractiveRenewal::class => [],
|
InteractiveRenewal::class => [],
|
||||||
PriceIncreaseConsent::class => [],
|
PriceIncreaseConsent::class => [],
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('companies', function (Blueprint $table) {
|
||||||
|
$table->boolean('report_include_deleted')->default(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('companies', function (Blueprint $table) {
|
||||||
|
//
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Models\CompanyGateway;
|
||||||
|
use App\Models\Gateway;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
|
||||||
|
$g = Gateway::find(50);
|
||||||
|
|
||||||
|
if($g)
|
||||||
|
{
|
||||||
|
$fields = json_decode($g->fields);
|
||||||
|
$fields->threeds = false;
|
||||||
|
|
||||||
|
$g->fields = json_encode($fields);
|
||||||
|
$g->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
CompanyGateway::where('gateway_key', 'f7ec488676d310683fb51802d076d713')->cursor()->each(function ($cg){
|
||||||
|
|
||||||
|
$config = $cg->getConfig();
|
||||||
|
$config->threeds = false;
|
||||||
|
$cg->setConfig($config);
|
||||||
|
|
||||||
|
$cg->save();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('payments', function (Blueprint $table) {
|
||||||
|
$table->string('idempotency_key', 64)->nullable()->index();
|
||||||
|
|
||||||
|
$table->unique(['company_id', 'idempotency_key']);
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
@ -74,7 +74,7 @@ class PaymentLibrariesSeeder extends Seeder
|
|||||||
['id' => 47, 'name' => 'Secure Trading', 'provider' => 'SecureTrading', 'key' => '231cb401487b9f15babe04b1ac4f7a27', 'fields' => '{"siteReference":"","username":"","password":"","applyThreeDSecure":false,"accountType":"ECOM"}'],
|
['id' => 47, 'name' => 'Secure Trading', 'provider' => 'SecureTrading', 'key' => '231cb401487b9f15babe04b1ac4f7a27', 'fields' => '{"siteReference":"","username":"","password":"","applyThreeDSecure":false,"accountType":"ECOM"}'],
|
||||||
['id' => 48, 'name' => 'SecPay', 'provider' => 'SecPay', 'key' => 'bad8699d581d9fa040e59c0bb721a76c', 'fields' => '{"mid":"","vpnPswd":"","remotePswd":"","usageType":"","confirmEmail":"","testStatus":"true","mailCustomer":"true","additionalOptions":""}'],
|
['id' => 48, 'name' => 'SecPay', 'provider' => 'SecPay', 'key' => 'bad8699d581d9fa040e59c0bb721a76c', 'fields' => '{"mid":"","vpnPswd":"","remotePswd":"","usageType":"","confirmEmail":"","testStatus":"true","mailCustomer":"true","additionalOptions":""}'],
|
||||||
['id' => 49, 'name' => 'WePay', 'provider' => 'WePay', 'is_offsite' => false, 'sort_order' => 3, 'key' => '8fdeed552015b3c7b44ed6c8ebd9e992', 'fields' => '{"accountId":"","accessToken":"","type":"goods","testMode":false,"feePayer":"payee"}'],
|
['id' => 49, 'name' => 'WePay', 'provider' => 'WePay', 'is_offsite' => false, 'sort_order' => 3, 'key' => '8fdeed552015b3c7b44ed6c8ebd9e992', 'fields' => '{"accountId":"","accessToken":"","type":"goods","testMode":false,"feePayer":"payee"}'],
|
||||||
['id' => 50, 'name' => 'Braintree', 'provider' => 'Braintree', 'sort_order' => 3, 'key' => 'f7ec488676d310683fb51802d076d713', 'fields' => '{"merchantId":"","merchantAccountId":"","publicKey":"","privateKey":"","testMode":false}'],
|
['id' => 50, 'name' => 'Braintree', 'provider' => 'Braintree', 'sort_order' => 3, 'key' => 'f7ec488676d310683fb51802d076d713', 'fields' => '{"merchantId":"","merchantAccountId":"","publicKey":"","privateKey":"","testMode":false,"threeds":false}'],
|
||||||
['id' => 51, 'name' => 'FirstData Payeezy', 'provider' => 'FirstData_Payeezy', 'key' => '30334a52fb698046572c627ca10412e8', 'fields' => '{"gatewayId":"","password":"","keyId":"","hmac":"","testMode":false}'],
|
['id' => 51, 'name' => 'FirstData Payeezy', 'provider' => 'FirstData_Payeezy', 'key' => '30334a52fb698046572c627ca10412e8', 'fields' => '{"gatewayId":"","password":"","keyId":"","hmac":"","testMode":false}'],
|
||||||
['id' => 52, 'name' => 'GoCardless', 'provider' => 'GoCardless', 'sort_order' => 9, 'is_offsite' => true, 'key' => 'b9886f9257f0c6ee7c302f1c74475f6c', 'fields' => '{"accessToken":"","webhookSecret":"","testMode":true}'],
|
['id' => 52, 'name' => 'GoCardless', 'provider' => 'GoCardless', 'sort_order' => 9, 'is_offsite' => true, 'key' => 'b9886f9257f0c6ee7c302f1c74475f6c', 'fields' => '{"accessToken":"","webhookSecret":"","testMode":true}'],
|
||||||
['id' => 53, 'name' => 'PagSeguro', 'provider' => 'PagSeguro', 'key' => 'ef498756b54db63c143af0ec433da803', 'fields' => '{"email":"","token":"","sandbox":false}'],
|
['id' => 53, 'name' => 'PagSeguro', 'provider' => 'PagSeguro', 'key' => 'ef498756b54db63c143af0ec433da803', 'fields' => '{"email":"","token":"","sandbox":false}'],
|
||||||
|
@ -4219,7 +4219,7 @@ $LANG = array(
|
|||||||
'max_companies_desc' => 'You have reached your maximum number of companies. Delete existing companies to migrate new ones.',
|
'max_companies_desc' => 'You have reached your maximum number of companies. Delete existing companies to migrate new ones.',
|
||||||
'migration_already_completed' => 'Company already migrated',
|
'migration_already_completed' => 'Company already migrated',
|
||||||
'migration_already_completed_desc' => 'Looks like you already migrated <b> :company_name </b>to the V5 version of the Invoice Ninja. In case you want to start over, you can force migrate to wipe existing data.',
|
'migration_already_completed_desc' => 'Looks like you already migrated <b> :company_name </b>to the V5 version of the Invoice Ninja. In case you want to start over, you can force migrate to wipe existing data.',
|
||||||
'payment_method_cannot_be_authorized_first' => 'This payment method can be can saved for future use, once you complete your first transaction. Don\'t forget to check "Store credit card details" during payment process.',
|
'payment_method_cannot_be_authorized_first' => 'This payment method can be can saved for future use, once you complete your first transaction. Don\'t forget to check "Store details" during payment process.',
|
||||||
'new_account' => 'New account',
|
'new_account' => 'New account',
|
||||||
'activity_100' => ':user created recurring invoice :recurring_invoice',
|
'activity_100' => ':user created recurring invoice :recurring_invoice',
|
||||||
'activity_101' => ':user updated recurring invoice :recurring_invoice',
|
'activity_101' => ':user updated recurring invoice :recurring_invoice',
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user