mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-08 17:04:30 -04:00
Merge pull request #8902 from turbo124/v5-develop
Add support for Libre Office
This commit is contained in:
commit
3225fc434b
@ -11,16 +11,18 @@
|
|||||||
|
|
||||||
namespace App\Console\Commands;
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
use App\DataMapper\CompanySettings;
|
use Faker\Factory;
|
||||||
use App\DataMapper\DefaultSettings;
|
use App\Models\User;
|
||||||
use App\Jobs\Mail\NinjaMailerJob;
|
|
||||||
use App\Jobs\Mail\NinjaMailerObject;
|
|
||||||
use App\Mail\Migration\MaxCompanies;
|
|
||||||
use App\Models\Account;
|
use App\Models\Account;
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
use App\Models\User;
|
use App\Mail\TestMailServer;
|
||||||
use Faker\Factory;
|
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
use App\Jobs\Mail\NinjaMailerJob;
|
||||||
|
use App\DataMapper\CompanySettings;
|
||||||
|
use App\DataMapper\DefaultSettings;
|
||||||
|
use App\Jobs\Mail\NinjaMailerObject;
|
||||||
|
use App\Mail\Migration\MaxCompanies;
|
||||||
|
use Illuminate\Support\Facades\Mail;
|
||||||
|
|
||||||
class SendTestEmails extends Command
|
class SendTestEmails extends Command
|
||||||
{
|
{
|
||||||
@ -55,39 +57,26 @@ class SendTestEmails extends Command
|
|||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
$faker = Factory::create();
|
|
||||||
|
|
||||||
$account = Account::factory()->create();
|
$to_user = User::first();
|
||||||
|
|
||||||
$user = User::factory()->create([
|
|
||||||
'account_id' => $account->id,
|
|
||||||
'confirmation_code' => '123',
|
|
||||||
'email' => $faker->safeEmail(),
|
|
||||||
'first_name' => 'John',
|
|
||||||
'last_name' => 'Doe',
|
|
||||||
]);
|
|
||||||
|
|
||||||
$company = Company::factory()->create([
|
|
||||||
'account_id' => $account->id,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$user->companies()->attach($company->id, [
|
|
||||||
'account_id' => $account->id,
|
|
||||||
'is_owner' => 1,
|
|
||||||
'is_admin' => 1,
|
|
||||||
'is_locked' => 0,
|
|
||||||
'permissions' => '',
|
|
||||||
'notifications' => CompanySettings::notificationDefaults(),
|
|
||||||
//'settings' => DefaultSettings::userSettings(),
|
|
||||||
'settings' => null,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$nmo = new NinjaMailerObject;
|
$nmo = new NinjaMailerObject;
|
||||||
$nmo->mailable = new MaxCompanies($user->account->companies()->first());
|
$nmo->mailable = new TestMailServer('Email Server Works!', config('mail.from.address'));
|
||||||
$nmo->company = $user->account->companies()->first();
|
$nmo->company = $to_user->account->companies()->first();
|
||||||
$nmo->settings = $user->account->companies()->first()->settings;
|
$nmo->settings = $to_user->account->companies()->first()->settings;
|
||||||
$nmo->to_user = $user;
|
$nmo->to_user = $to_user;
|
||||||
|
|
||||||
(new NinjaMailerJob($nmo))->handle();
|
try {
|
||||||
|
|
||||||
|
Mail::raw("Test Message", function ($message) {
|
||||||
|
$message->to(config('mail.from.address'))
|
||||||
|
->from(config('mail.from.address'), config('mail.from.name'))
|
||||||
|
->subject('Test Email');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
} catch(\Exception $e) {
|
||||||
|
$this->info("Error sending email: " . $e->getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@ class BankIntegrationFactory
|
|||||||
$bank_integration->bank_account_type = '';
|
$bank_integration->bank_account_type = '';
|
||||||
$bank_integration->balance = 0;
|
$bank_integration->balance = 0;
|
||||||
$bank_integration->currency = '';
|
$bank_integration->currency = '';
|
||||||
|
$bank_integration->auto_sync = 1;
|
||||||
|
|
||||||
return $bank_integration;
|
return $bank_integration;
|
||||||
}
|
}
|
||||||
|
@ -136,8 +136,13 @@ class TaskFilters extends QueryFilters
|
|||||||
|
|
||||||
$status_parameters = explode(',', $value);
|
$status_parameters = explode(',', $value);
|
||||||
|
|
||||||
if(count($status_parameters) >= 1)
|
if(count($status_parameters) >= 1){
|
||||||
$this->builder->whereIn('status_id', $this->transformKeys($status_parameters));
|
|
||||||
|
$this->builder->where(function ($query) use ($status_parameters) {
|
||||||
|
$query->whereIn('status_id', $this->transformKeys($status_parameters))->whereNull('invoice_id');
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,8 @@ class YodleeController extends BaseController
|
|||||||
$bank_integration->balance = $account['current_balance'];
|
$bank_integration->balance = $account['current_balance'];
|
||||||
$bank_integration->currency = $account['account_currency'];
|
$bank_integration->currency = $account['account_currency'];
|
||||||
$bank_integration->from_date = now()->subYear();
|
$bank_integration->from_date = now()->subYear();
|
||||||
|
$bank_integration->auto_sync = true;
|
||||||
|
|
||||||
$bank_integration->save();
|
$bank_integration->save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -166,8 +167,8 @@ class YodleeController extends BaseController
|
|||||||
public function refreshWebhook(Request $request)
|
public function refreshWebhook(Request $request)
|
||||||
{
|
{
|
||||||
//we should ignore this one
|
//we should ignore this one
|
||||||
nlog("yodlee refresh");
|
// nlog("yodlee refresh");
|
||||||
nlog($request->all());
|
// nlog($request->all());
|
||||||
|
|
||||||
return response()->json(['message' => 'Success'], 200);
|
return response()->json(['message' => 'Success'], 200);
|
||||||
|
|
||||||
@ -236,8 +237,8 @@ class YodleeController extends BaseController
|
|||||||
public function refreshUpdatesWebhook(Request $request)
|
public function refreshUpdatesWebhook(Request $request)
|
||||||
{
|
{
|
||||||
//notifies a user if there are problems with yodlee accessing the data
|
//notifies a user if there are problems with yodlee accessing the data
|
||||||
nlog("update refresh");
|
// nlog("update refresh");
|
||||||
nlog($request->all());
|
// nlog($request->all());
|
||||||
|
|
||||||
return response()->json(['message' => 'Success'], 200);
|
return response()->json(['message' => 'Success'], 200);
|
||||||
|
|
||||||
|
@ -230,6 +230,8 @@ class BankIntegrationController extends BaseController
|
|||||||
$bank_integration->nickname = $account['nickname'];
|
$bank_integration->nickname = $account['nickname'];
|
||||||
$bank_integration->balance = $account['current_balance'];
|
$bank_integration->balance = $account['current_balance'];
|
||||||
$bank_integration->currency = $account['account_currency'];
|
$bank_integration->currency = $account['account_currency'];
|
||||||
|
$bank_integration->auto_sync = true;
|
||||||
|
|
||||||
$bank_integration->save();
|
$bank_integration->save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,9 @@ namespace App\Http\Controllers;
|
|||||||
use App\Utils\Ninja;
|
use App\Utils\Ninja;
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
use App\Models\Account;
|
use App\Models\Account;
|
||||||
|
use App\Models\Company;
|
||||||
|
use App\Models\SystemLog;
|
||||||
|
use Postmark\PostmarkClient;
|
||||||
use Illuminate\Http\Response;
|
use Illuminate\Http\Response;
|
||||||
use App\Factory\ClientFactory;
|
use App\Factory\ClientFactory;
|
||||||
use App\Filters\ClientFilters;
|
use App\Filters\ClientFilters;
|
||||||
@ -36,6 +39,8 @@ use App\Http\Requests\Client\CreateClientRequest;
|
|||||||
use App\Http\Requests\Client\UpdateClientRequest;
|
use App\Http\Requests\Client\UpdateClientRequest;
|
||||||
use App\Http\Requests\Client\UploadClientRequest;
|
use App\Http\Requests\Client\UploadClientRequest;
|
||||||
use App\Http\Requests\Client\DestroyClientRequest;
|
use App\Http\Requests\Client\DestroyClientRequest;
|
||||||
|
use App\Http\Requests\Client\ReactivateClientEmailRequest;
|
||||||
|
use App\Jobs\PostMark\ProcessPostmarkWebhook;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class ClientController.
|
* Class ClientController.
|
||||||
@ -219,7 +224,7 @@ class ClientController extends BaseController
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return $this->listResponse(Client::withTrashed()->company()->whereIn('id', $request->ids));
|
return $this->listResponse(Client::query()->withTrashed()->company()->whereIn('id', $request->ids));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -313,4 +318,61 @@ class ClientController extends BaseController
|
|||||||
|
|
||||||
return $this->itemResponse($client->fresh());
|
return $this->itemResponse($client->fresh());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reactivate a client email
|
||||||
|
*
|
||||||
|
* @param ReactivateClientEmailRequest $request
|
||||||
|
* @param string $bounce_id //could also be the invitationId
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
|
public function reactivateEmail(ReactivateClientEmailRequest $request, string $bounce_id)
|
||||||
|
{
|
||||||
|
/** @var \App\Models\User $user */
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
if(stripos($bounce_id, '-') !== false){
|
||||||
|
$log =
|
||||||
|
SystemLog::query()
|
||||||
|
->where('company_id', $user->company()->id)
|
||||||
|
->where('type_id', SystemLog::TYPE_WEBHOOK_RESPONSE)
|
||||||
|
->where('category_id', SystemLog::CATEGORY_MAIL)
|
||||||
|
->whereJsonContains('log', ['MessageID' => $bounce_id])
|
||||||
|
->orderBy('id', 'desc')
|
||||||
|
->first();
|
||||||
|
|
||||||
|
$resolved_bounce_id = false;
|
||||||
|
|
||||||
|
if($log && ($log?->log['ID'] ?? false)){
|
||||||
|
$resolved_bounce_id = $log->log['ID'] ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!$resolved_bounce_id){
|
||||||
|
$ppwebhook = new ProcessPostmarkWebhook([]);
|
||||||
|
$resolved_bounce_id = $ppwebhook->getBounceId($bounce_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!$resolved_bounce_id){
|
||||||
|
return response()->json(['message' => 'Bounce ID not found'], 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$bounce_id = $resolved_bounce_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
$postmark = new PostmarkClient(config('services.postmark.token'));
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
$response = $postmark->activateBounce((int)$bounce_id);
|
||||||
|
|
||||||
|
return response()->json(['message' => 'Success'], 200);
|
||||||
|
|
||||||
|
}
|
||||||
|
catch(\Exception $e){
|
||||||
|
|
||||||
|
return response()->json(['message' => $e->getMessage(), 400]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ class PostMarkController extends BaseController
|
|||||||
public function webhook(Request $request)
|
public function webhook(Request $request)
|
||||||
{
|
{
|
||||||
if ($request->header('X-API-SECURITY') && $request->header('X-API-SECURITY') == config('services.postmark.token')) {
|
if ($request->header('X-API-SECURITY') && $request->header('X-API-SECURITY') == config('services.postmark.token')) {
|
||||||
ProcessPostmarkWebhook::dispatch($request->all());
|
ProcessPostmarkWebhook::dispatch($request->all())->delay(10);
|
||||||
|
|
||||||
return response()->json(['message' => 'Success'], 200);
|
return response()->json(['message' => 'Success'], 200);
|
||||||
}
|
}
|
||||||
|
@ -100,18 +100,20 @@ class PreviewController extends BaseController
|
|||||||
/** Update necessary objecty props */
|
/** Update necessary objecty props */
|
||||||
if(!$entity_obj->id) {
|
if(!$entity_obj->id) {
|
||||||
$entity_obj->design_id = intval($this->decodePrimaryKey($settings->{$entity_prop."_design_id"}));
|
$entity_obj->design_id = intval($this->decodePrimaryKey($settings->{$entity_prop."_design_id"}));
|
||||||
$entity_obj->footer = $settings->{$entity_prop."_footer"};
|
$entity_obj->footer = empty($entity_obj->footer) ? $settings->{$entity_prop."_footer"} : $entity_obj->footer;
|
||||||
$entity_obj->terms = $settings->{$entity_prop."_terms"};
|
$entity_obj->terms = empty($entity_obj->term) ? $settings->{$entity_prop."_terms"} : $entity_obj->terms;
|
||||||
$entity_obj->public_notes = $request->getClient()->public_notes;
|
$entity_obj->public_notes = empty($entity_obj->public_notes) ? $request->getClient()->public_notes : $entity_obj->public_notes;
|
||||||
$invitation->{$request->entity} = $entity_obj;
|
$invitation->{$request->entity} = $entity_obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(empty($entity_obj->design_id))
|
||||||
|
$entity_obj->design_id = intval($this->decodePrimaryKey($settings->{$entity_prop."_design_id"}));
|
||||||
|
|
||||||
/** Generate variables */
|
/** Generate variables */
|
||||||
$html = new HtmlEngine($invitation);
|
$html = new HtmlEngine($invitation);
|
||||||
$html->settings = $settings;
|
$html->settings = $settings;
|
||||||
$variables = $html->generateLabelsAndValues();
|
$variables = $html->generateLabelsAndValues();
|
||||||
|
|
||||||
|
|
||||||
$design = \App\Models\Design::query()->withTrashed()->find($entity_obj->design_id ?? 2);
|
$design = \App\Models\Design::query()->withTrashed()->find($entity_obj->design_id ?? 2);
|
||||||
|
|
||||||
/* Catch all in case migration doesn't pass back a valid design */
|
/* Catch all in case migration doesn't pass back a valid design */
|
||||||
|
@ -117,6 +117,7 @@ class StripeConnectController extends BaseController
|
|||||||
'refresh_token' => $response->refresh_token,
|
'refresh_token' => $response->refresh_token,
|
||||||
'access_token' => $response->access_token,
|
'access_token' => $response->access_token,
|
||||||
'appleDomainVerification' => '',
|
'appleDomainVerification' => '',
|
||||||
|
// "statementDescriptor" => "",
|
||||||
];
|
];
|
||||||
|
|
||||||
$company_gateway->setConfig($payload);
|
$company_gateway->setConfig($payload);
|
||||||
|
28
app/Http/Requests/Client/ReactivateClientEmailRequest.php
Normal file
28
app/Http/Requests/Client/ReactivateClientEmailRequest.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Client;
|
||||||
|
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
|
||||||
|
class ReactivateClientEmailRequest extends Request
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -20,7 +20,7 @@ class Request extends FormRequest
|
|||||||
use MakesHash;
|
use MakesHash;
|
||||||
use RuntimeFormRequest;
|
use RuntimeFormRequest;
|
||||||
|
|
||||||
protected $file_validation = 'sometimes|file|mimes:png,ai,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx,webp,xml,zip,csv|max:100000';
|
protected $file_validation = 'sometimes|file|mimes:png,ai,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx,webp,xml,zip,csv,ods,odt,odp|max:100000';
|
||||||
/**
|
/**
|
||||||
* Get the validation rules that apply to the request.
|
* Get the validation rules that apply to the request.
|
||||||
*
|
*
|
||||||
|
@ -83,11 +83,21 @@ class EmailPayment implements ShouldQueue
|
|||||||
|
|
||||||
$invitation = null;
|
$invitation = null;
|
||||||
|
|
||||||
|
$nmo = new NinjaMailerObject;
|
||||||
|
|
||||||
if ($this->payment->invoices && $this->payment->invoices->count() >= 1) {
|
if ($this->payment->invoices && $this->payment->invoices->count() >= 1) {
|
||||||
$invitation = $this->payment->invoices->first()->invitations()->first();
|
|
||||||
|
if($this->contact){
|
||||||
|
$invitation = $this->payment->invoices->first()->invitations()->where('client_contact_id', $this->contact->id)->first();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
$invitation = $this->payment->invoices->first()->invitations()->first();
|
||||||
|
|
||||||
|
if($invitation)
|
||||||
|
$nmo->invitation = $invitation;
|
||||||
}
|
}
|
||||||
|
|
||||||
$nmo = new NinjaMailerObject;
|
|
||||||
$nmo->mailable = new TemplateEmail($email_builder, $this->contact, $invitation);
|
$nmo->mailable = new TemplateEmail($email_builder, $this->contact, $invitation);
|
||||||
$nmo->to_user = $this->contact;
|
$nmo->to_user = $this->contact;
|
||||||
$nmo->settings = $this->settings;
|
$nmo->settings = $this->settings;
|
||||||
|
@ -88,11 +88,22 @@ class EmailRefundPayment implements ShouldQueue
|
|||||||
|
|
||||||
$invitation = null;
|
$invitation = null;
|
||||||
|
|
||||||
|
$nmo = new NinjaMailerObject;
|
||||||
|
|
||||||
if ($this->payment->invoices && $this->payment->invoices->count() >= 1) {
|
if ($this->payment->invoices && $this->payment->invoices->count() >= 1) {
|
||||||
$invitation = $this->payment->invoices->first()->invitations()->first();
|
|
||||||
|
if($this->contact) {
|
||||||
|
$invitation = $this->payment->invoices->first()->invitations()->where('client_contact_id', $this->contact->id)->first();
|
||||||
|
} else {
|
||||||
|
$invitation = $this->payment->invoices->first()->invitations()->first();
|
||||||
|
}
|
||||||
|
|
||||||
|
if($invitation)
|
||||||
|
$nmo->invitation = $invitation;
|
||||||
}
|
}
|
||||||
|
|
||||||
$nmo = new NinjaMailerObject;
|
|
||||||
|
|
||||||
$nmo->mailable = new TemplateEmail($email_builder, $this->contact, $invitation);
|
$nmo->mailable = new TemplateEmail($email_builder, $this->contact, $invitation);
|
||||||
$nmo->to_user = $this->contact;
|
$nmo->to_user = $this->contact;
|
||||||
$nmo->settings = $this->settings;
|
$nmo->settings = $this->settings;
|
||||||
|
@ -339,6 +339,32 @@ class ProcessPostmarkWebhook implements ShouldQueue
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getRawMessage(string $message_id)
|
||||||
|
{
|
||||||
|
|
||||||
|
$postmark = new PostmarkClient(config('services.postmark.token'));
|
||||||
|
$messageDetail = $postmark->getOutboundMessageDetails($message_id);
|
||||||
|
return $messageDetail;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function getBounceId(string $message_id): ?int
|
||||||
|
{
|
||||||
|
|
||||||
|
$messageDetail = $this->getRawMessage($message_id);
|
||||||
|
|
||||||
|
|
||||||
|
$event = collect($messageDetail->messageevents)->first(function ($event) {
|
||||||
|
|
||||||
|
return $event?->Details?->BounceID ?? false;
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
return $event?->Details?->BounceID ?? null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private function fetchMessage(): array
|
private function fetchMessage(): array
|
||||||
{
|
{
|
||||||
if(strlen($this->request['MessageID']) < 1){
|
if(strlen($this->request['MessageID']) < 1){
|
||||||
@ -356,6 +382,7 @@ class ProcessPostmarkWebhook implements ShouldQueue
|
|||||||
$events = collect($messageDetail->messageevents)->map(function ($event) {
|
$events = collect($messageDetail->messageevents)->map(function ($event) {
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
'bounce_id' => $event?->Details?->BounceID ?? '',
|
||||||
'recipient' => $event->Recipient ?? '',
|
'recipient' => $event->Recipient ?? '',
|
||||||
'status' => $event->Type ?? '',
|
'status' => $event->Type ?? '',
|
||||||
'delivery_message' => $event->Details->DeliveryMessage ?? $event->Details->Summary ?? '',
|
'delivery_message' => $event->Details->DeliveryMessage ?? $event->Details->Summary ?? '',
|
||||||
|
@ -41,6 +41,7 @@ class MailSentListener implements ShouldQueue
|
|||||||
*/
|
*/
|
||||||
public function handle(MessageSent $event)
|
public function handle(MessageSent $event)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!Ninja::isHosted()) {
|
if (!Ninja::isHosted()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,6 @@ use Illuminate\Queue\SerializesModels;
|
|||||||
|
|
||||||
class TestMailServer extends Mailable
|
class TestMailServer extends Mailable
|
||||||
{
|
{
|
||||||
// use Queueable, SerializesModels;
|
|
||||||
|
|
||||||
public $support_messages;
|
public $support_messages;
|
||||||
|
|
||||||
|
@ -306,7 +306,7 @@ class Client extends BaseModel implements HasLocalePreference
|
|||||||
return $this->hasMany(ClientContact::class)->where('is_primary', true);
|
return $this->hasMany(ClientContact::class)->where('is_primary', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function company() :BelongsTo
|
public function company(): BelongsTo
|
||||||
{
|
{
|
||||||
return $this->belongsTo(Company::class);
|
return $this->belongsTo(Company::class);
|
||||||
}
|
}
|
||||||
|
@ -786,6 +786,26 @@ class Company extends BaseModel
|
|||||||
return $this->hasMany(CompanyUser::class)->withTrashed();
|
return $this->hasMany(CompanyUser::class)->withTrashed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function invoice_invitations(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(InvoiceInvitation::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function quote_invitations(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(QuoteInvitation::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function credit_invitations(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(CreditInvitation::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function purchase_order_invitations(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(PurchaseOrderInvitation::class);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return \App\Models\User|null
|
* @return \App\Models\User|null
|
||||||
*/
|
*/
|
||||||
|
@ -33,6 +33,7 @@ class CreditInvitationTransformer extends EntityTransformer
|
|||||||
'created_at' => (int) $invitation->created_at,
|
'created_at' => (int) $invitation->created_at,
|
||||||
'email_status' => $invitation->email_status ?: '',
|
'email_status' => $invitation->email_status ?: '',
|
||||||
'email_error' => (string) $invitation->email_error,
|
'email_error' => (string) $invitation->email_error,
|
||||||
|
'message_id' => (string) $invitation->message_id ?: '',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@ class InvoiceInvitationTransformer extends EntityTransformer
|
|||||||
'created_at' => (int) $invitation->created_at,
|
'created_at' => (int) $invitation->created_at,
|
||||||
'email_status' => $invitation->email_status ?: '',
|
'email_status' => $invitation->email_status ?: '',
|
||||||
'email_error' => (string) $invitation->email_error,
|
'email_error' => (string) $invitation->email_error,
|
||||||
|
'message_id' => (string) $invitation->message_id ?: '',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ class PurchaseOrderInvitationTransformer extends EntityTransformer
|
|||||||
'created_at' => (int) $invitation->created_at,
|
'created_at' => (int) $invitation->created_at,
|
||||||
'email_status' => $invitation->email_status ?: '',
|
'email_status' => $invitation->email_status ?: '',
|
||||||
'email_error' => (string) $invitation->email_error,
|
'email_error' => (string) $invitation->email_error,
|
||||||
|
'message_id' => (string) $invitation->message_id ?: '',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@ class QuoteInvitationTransformer extends EntityTransformer
|
|||||||
'created_at' => (int) $invitation->created_at,
|
'created_at' => (int) $invitation->created_at,
|
||||||
'email_status' => $invitation->email_status ?: '',
|
'email_status' => $invitation->email_status ?: '',
|
||||||
'email_error' => (string) $invitation->email_error,
|
'email_error' => (string) $invitation->email_error,
|
||||||
|
'message_id' => (string) $invitation->message_id ?: '',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@ class RecurringInvoiceInvitationTransformer extends EntityTransformer
|
|||||||
'created_at' => (int) $invitation->created_at,
|
'created_at' => (int) $invitation->created_at,
|
||||||
'email_status' => $invitation->email_status ?: '',
|
'email_status' => $invitation->email_status ?: '',
|
||||||
'email_error' => (string) $invitation->email_error,
|
'email_error' => (string) $invitation->email_error,
|
||||||
|
'message_id' => (string) $invitation->message_id ?: '',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
13076
openapi/api-docs.yaml
13076
openapi/api-docs.yaml
File diff suppressed because it is too large
Load Diff
@ -653,5 +653,91 @@
|
|||||||
$ref: '#/components/responses/429'
|
$ref: '#/components/responses/429'
|
||||||
5XX:
|
5XX:
|
||||||
description: 'Server error'
|
description: 'Server error'
|
||||||
|
default:
|
||||||
|
$ref: '#/components/responses/default'
|
||||||
|
/api/v1/reactivate_email/{bounce_id}:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- clients
|
||||||
|
summary: 'Removes email suppression of a user in the system'
|
||||||
|
description: 'Emails are suppressed by PostMark, when they receive a Hard bounce / Spam Complaint. This endpoint allows you to remove the suppression and send emails to the user again.'
|
||||||
|
operationId: reactivateEmail
|
||||||
|
parameters:
|
||||||
|
- $ref: '#/components/parameters/X-API-TOKEN'
|
||||||
|
- $ref: '#/components/parameters/X-Requested-With'
|
||||||
|
- $ref: '#/components/parameters/include'
|
||||||
|
- name: bounce_id
|
||||||
|
in: path
|
||||||
|
description: 'The postmark Bounce ID reference'
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
format: string
|
||||||
|
example: 123243
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: 'Success'
|
||||||
|
headers:
|
||||||
|
X-MINIMUM-CLIENT-VERSION:
|
||||||
|
$ref: '#/components/headers/X-MINIMUM-CLIENT-VERSION'
|
||||||
|
X-RateLimit-Remaining:
|
||||||
|
$ref: '#/components/headers/X-RateLimit-Remaining'
|
||||||
|
X-RateLimit-Limit:
|
||||||
|
$ref: '#/components/headers/X-RateLimit-Limit'
|
||||||
|
400:
|
||||||
|
description: 'Postmark exception - generated if the suppression cannot be removed for any reason'
|
||||||
|
401:
|
||||||
|
$ref: '#/components/responses/401'
|
||||||
|
403:
|
||||||
|
$ref: '#/components/responses/403'
|
||||||
|
422:
|
||||||
|
$ref: '#/components/responses/422'
|
||||||
|
429:
|
||||||
|
$ref: '#/components/responses/429'
|
||||||
|
5XX:
|
||||||
|
description: 'Server error'
|
||||||
|
default:
|
||||||
|
$ref: '#/components/responses/default'
|
||||||
|
/api/v1/clients/{client}/updateTaxData:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- clients
|
||||||
|
summary: 'Update tax data'
|
||||||
|
description: 'Updates the clients tax data - if their address has changed'
|
||||||
|
operationId: updateClientTaxData
|
||||||
|
parameters:
|
||||||
|
- $ref: '#/components/parameters/X-API-TOKEN'
|
||||||
|
- $ref: '#/components/parameters/X-Requested-With'
|
||||||
|
- $ref: '#/components/parameters/include'
|
||||||
|
- name: client
|
||||||
|
in: path
|
||||||
|
description: 'The Client Hashed ID reference'
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
format: string
|
||||||
|
example: V2J234DFA
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: 'Success'
|
||||||
|
headers:
|
||||||
|
X-MINIMUM-CLIENT-VERSION:
|
||||||
|
$ref: '#/components/headers/X-MINIMUM-CLIENT-VERSION'
|
||||||
|
X-RateLimit-Remaining:
|
||||||
|
$ref: '#/components/headers/X-RateLimit-Remaining'
|
||||||
|
X-RateLimit-Limit:
|
||||||
|
$ref: '#/components/headers/X-RateLimit-Limit'
|
||||||
|
400:
|
||||||
|
description: 'Postmark exception - generated if the suppression cannot be removed for any reason'
|
||||||
|
401:
|
||||||
|
$ref: '#/components/responses/401'
|
||||||
|
403:
|
||||||
|
$ref: '#/components/responses/403'
|
||||||
|
422:
|
||||||
|
$ref: '#/components/responses/422'
|
||||||
|
429:
|
||||||
|
$ref: '#/components/responses/429'
|
||||||
|
5XX:
|
||||||
|
description: 'Server error'
|
||||||
default:
|
default:
|
||||||
$ref: '#/components/responses/default'
|
$ref: '#/components/responses/default'
|
@ -1,4 +1,4 @@
|
|||||||
@if ($entity->documents->count() > 0 || $entity->company->documents->count() > 0 || ($entity->expense && $entity->expense->invoice_documents) || ($entity->task && $entity->company->invoice_task_documents))
|
@if ($entity->documents()->where('is_public',1)->count() > 0 || $entity->company->documents()->where('is_public',1)->count() > 0 || ($entity->expense && $entity->expense->invoice_documents) || ($entity->task && $entity->company->invoice_task_documents))
|
||||||
<div class="bg-white shadow sm:rounded-lg my-4">
|
<div class="bg-white shadow sm:rounded-lg my-4">
|
||||||
<div class="px-4 py-5 sm:p-6">
|
<div class="px-4 py-5 sm:p-6">
|
||||||
<div class="sm:flex sm:items-start sm:justify-between">
|
<div class="sm:flex sm:items-start sm:justify-between">
|
||||||
|
@ -164,6 +164,8 @@ Route::group(['middleware' => ['throttle:api', 'api_db', 'token_auth', 'locale']
|
|||||||
Route::post('clients/{client}/{mergeable_client}/merge', [ClientController::class, 'merge'])->name('clients.merge')->middleware('password_protected');
|
Route::post('clients/{client}/{mergeable_client}/merge', [ClientController::class, 'merge'])->name('clients.merge')->middleware('password_protected');
|
||||||
Route::post('clients/bulk', [ClientController::class, 'bulk'])->name('clients.bulk');
|
Route::post('clients/bulk', [ClientController::class, 'bulk'])->name('clients.bulk');
|
||||||
|
|
||||||
|
Route::post('reactivate_email/{bounce_id}', [ClientController::class, 'reactivateEmail'])->name('clients.reactivate_email');
|
||||||
|
|
||||||
Route::post('filters/{entity}', [FilterController::class, 'index'])->name('filters');
|
Route::post('filters/{entity}', [FilterController::class, 'index'])->name('filters');
|
||||||
|
|
||||||
Route::resource('client_gateway_tokens', ClientGatewayTokenController::class);
|
Route::resource('client_gateway_tokens', ClientGatewayTokenController::class);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user