1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-10 13:12:50 +01:00

Merge pull request #9395 from turbo124/v5-develop

Fixes for tests / name spaces - e-invoicing
This commit is contained in:
David Bomba 2024-03-21 19:38:47 +11:00 committed by GitHub
commit e8f9577bb8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
37 changed files with 172 additions and 89 deletions

View File

@ -479,6 +479,8 @@ class CompanySettings extends BaseSettings
public $e_invoice_type = 'EN16931'; public $e_invoice_type = 'EN16931';
public $e_quote_type = 'OrderX_Comfort';
public $default_expense_payment_type_id = '0'; public $default_expense_payment_type_id = '0';
public $enable_e_invoice = false; public $enable_e_invoice = false;
@ -502,6 +504,7 @@ class CompanySettings extends BaseSettings
public $enable_rappen_rounding = false; public $enable_rappen_rounding = false;
public static $casts = [ public static $casts = [
'e_quote_type' => 'string',
'enable_rappen_rounding' => 'bool', 'enable_rappen_rounding' => 'bool',
'use_unapplied_payment' => 'string', 'use_unapplied_payment' => 'string',
'show_pdfhtml_on_mobile' => 'bool', 'show_pdfhtml_on_mobile' => 'bool',

View File

@ -427,8 +427,11 @@ class BaseExport
protected array $task_report_keys = [ protected array $task_report_keys = [
'start_date' => 'task.start_date', 'start_date' => 'task.start_date',
'start_time' => 'task.start_time',
'end_date' => 'task.end_date', 'end_date' => 'task.end_date',
'end_time' => 'task.end_time',
'duration' => 'task.duration', 'duration' => 'task.duration',
'duration_words' => 'task.duration_words',
'rate' => 'task.rate', 'rate' => 'task.rate',
'number' => 'task.number', 'number' => 'task.number',
'description' => 'task.description', 'description' => 'task.description',

View File

@ -11,18 +11,19 @@
namespace App\Export\CSV; namespace App\Export\CSV;
use App\Export\Decorators\Decorator;
use App\Libraries\MultiDB;
use App\Models\Company;
use App\Models\DateFormat;
use App\Models\Task; use App\Models\Task;
use App\Models\Timezone;
use App\Transformers\TaskTransformer;
use App\Utils\Ninja; use App\Utils\Ninja;
use Illuminate\Database\Eloquent\Builder; use League\Csv\Writer;
use App\Models\Company;
use App\Models\Timezone;
use App\Libraries\MultiDB;
use App\Models\DateFormat;
use Carbon\CarbonInterval;
use Illuminate\Support\Carbon; use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\App;
use League\Csv\Writer; use App\Export\Decorators\Decorator;
use App\Transformers\TaskTransformer;
use Illuminate\Database\Eloquent\Builder;
class TaskExport extends BaseExport class TaskExport extends BaseExport
{ {
@ -177,19 +178,26 @@ class TaskExport extends BaseExport
foreach ($logs as $key => $item) { foreach ($logs as $key => $item) {
if (in_array('task.start_date', $this->input['report_keys']) || in_array('start_date', $this->input['report_keys'])) { if (in_array('task.start_date', $this->input['report_keys']) || in_array('start_date', $this->input['report_keys'])) {
$entity['task.start_date'] = Carbon::createFromTimeStamp($item[0])->setTimezone($timezone_name)->format($date_format_default); $carbon_object = Carbon::createFromTimeStamp($item[0])->setTimezone($timezone_name);
$entity['task.start_date'] = $carbon_object->format($date_format_default);
$entity['task.start_time'] = $carbon_object->format('H:i:s');
} }
if ((in_array('task.end_date', $this->input['report_keys']) || in_array('end_date', $this->input['report_keys'])) && $item[1] > 0) { if ((in_array('task.end_date', $this->input['report_keys']) || in_array('end_date', $this->input['report_keys'])) && $item[1] > 0) {
$entity['task.end_date'] = Carbon::createFromTimeStamp($item[1])->setTimezone($timezone_name)->format($date_format_default); $carbon_object = Carbon::createFromTimeStamp($item[1])->setTimezone($timezone_name);
$entity['task.end_date'] = $carbon_object->format($date_format_default);
$entity['task.end_time'] = $carbon_object->format('H:i:s');
} }
if ((in_array('task.end_date', $this->input['report_keys']) || in_array('end_date', $this->input['report_keys'])) && $item[1] == 0) { if ((in_array('task.end_date', $this->input['report_keys']) || in_array('end_date', $this->input['report_keys'])) && $item[1] == 0) {
$entity['task.end_date'] = ctrans('texts.is_running'); $entity['task.end_date'] = ctrans('texts.is_running');
$entity['task.end_time'] = ctrans('texts.is_running');
} }
if (in_array('task.duration', $this->input['report_keys']) || in_array('duration', $this->input['report_keys'])) { if (in_array('task.duration', $this->input['report_keys']) || in_array('duration', $this->input['report_keys'])) {
$entity['task.duration'] = $task->calcDuration(); $seconds = $task->calcDuration();
$entity['task.duration'] = $seconds;
$entity['task.duration_words'] = CarbonInterval::seconds($seconds)->locale($this->company->locale())->cascade()->forHumans();
} }
$entity = $this->decorateAdvancedFields($task, $entity); $entity = $this->decorateAdvancedFields($task, $entity);
@ -197,8 +205,12 @@ class TaskExport extends BaseExport
$this->storage_array[] = $entity; $this->storage_array[] = $entity;
$entity['task.start_date'] = ''; $entity['task.start_date'] = '';
$entity['task.start_time'] = '';
$entity['task.end_date'] = ''; $entity['task.end_date'] = '';
$entity['task.end_time'] = '';
$entity['task.duration'] = ''; $entity['task.duration'] = '';
$entity['task.duration_words'] = '';
} }
} }

View File

@ -23,7 +23,7 @@ class InvoiceDecorator extends Decorator implements DecoratorInterface
$invoice = $entity; $invoice = $entity;
} elseif($entity->invoice) { } elseif($entity->invoice) {
$invoice = $entity->invoice; $invoice = $entity->invoice;
} elseif($entity->invoices()->exists()) { } elseif(method_exists($entity, 'invoices') && $entity->invoices()->exists()) {
$invoice = $entity->invoices()->first(); $invoice = $entity->invoices()->first();
} }

View File

@ -246,8 +246,6 @@ class InvoiceSum
if ($this->invoice->status_id != Invoice::STATUS_DRAFT) { if ($this->invoice->status_id != Invoice::STATUS_DRAFT) {
if ($this->invoice->amount != $this->invoice->balance) { if ($this->invoice->amount != $this->invoice->balance) {
// $paid_to_date = $this->invoice->amount - $this->invoice->balance;
$this->invoice->balance = Number::roundValue($this->getTotal(), $this->precision) - $this->invoice->paid_to_date; //21-02-2024 cannot use the calculated $paid_to_date here as it could send the balance backward. $this->invoice->balance = Number::roundValue($this->getTotal(), $this->precision) - $this->invoice->paid_to_date; //21-02-2024 cannot use the calculated $paid_to_date here as it could send the balance backward.
} else { } else {
$this->invoice->balance = Number::roundValue($this->getTotal(), $this->precision); $this->invoice->balance = Number::roundValue($this->getTotal(), $this->precision);
@ -256,8 +254,10 @@ class InvoiceSum
/* Set new calculated total */ /* Set new calculated total */
$this->invoice->amount = $this->formatValue($this->getTotal(), $this->precision); $this->invoice->amount = $this->formatValue($this->getTotal(), $this->precision);
if($this->rappen_rounding) if($this->rappen_rounding){
$this->invoice->amount = $this->roundRappen($this->invoice->amount); $this->invoice->amount = $this->roundRappen($this->invoice->amount);
$this->invoice->balance = $this->roundRappen($this->invoice->balance);
}
$this->invoice->total_taxes = $this->getTotalTaxes(); $this->invoice->total_taxes = $this->getTotalTaxes();

View File

@ -272,11 +272,11 @@ class InvoiceSumInclusive
} }
/* Set new calculated total */ /* Set new calculated total */
/** @todo - rappen rounding here */
$this->invoice->amount = $this->formatValue($this->getTotal(), $this->precision); $this->invoice->amount = $this->formatValue($this->getTotal(), $this->precision);
if($this->rappen_rounding) { if($this->rappen_rounding) {
$this->invoice->amount = $this->roundRappen($this->invoice->amount); $this->invoice->amount = $this->roundRappen($this->invoice->amount);
$this->invoice->balance = $this->roundRappen($this->invoice->balance);
} }
$this->invoice->total_taxes = $this->getTotalTaxes(); $this->invoice->total_taxes = $this->getTotalTaxes();

View File

@ -390,13 +390,20 @@ class LoginController extends BaseController
$truth->setUser($user); $truth->setUser($user);
$truth->setCompany($set_company); $truth->setCompany($set_company);
$user->account->companies->each(function ($company) use ($user) { //21-03-2024
if ($company->tokens()->where('is_system', true)->count() == 0) { $cu->each(function ($cu){
(new CreateCompanyToken($company, $user, request()->server('HTTP_USER_AGENT')))->handle(); if(CompanyToken::where('company_id', $cu->company_id)->where('user_id', $cu->user_id)->where('is_system', true)->doesntExist()){
(new CreateCompanyToken($cu->company, $cu->user, request()->server('HTTP_USER_AGENT')))->handle();
} }
}); });
$truth->setCompanyToken(CompanyToken::where('user_id', $user->id)->where('company_id', $set_company->id)->first()); // $user->account->companies->each(function ($company) use ($user) {
// if ($company->tokens()->where('user_id',$user->id)->where('is_system', true)->count() == 0) {
// (new CreateCompanyToken($company, $user, request()->server('HTTP_USER_AGENT')))->handle();
// }
// });
$truth->setCompanyToken(CompanyToken::where('user_id', $user->id)->where('company_id', $set_company->id)->where('is_system', true)->first());
return CompanyUser::query()->where('user_id', $user->id); return CompanyUser::query()->where('user_id', $user->id);
} }

View File

@ -90,14 +90,13 @@ 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->integration_type = BankIntegration::INTEGRATION_TYPE_YODLEE;
$bank_integration->auto_sync = true; $bank_integration->auto_sync = true;
$bank_integration->save(); $bank_integration->save();
} }
} }
$company->account->bank_integrations->where("integration_type", BankIntegration::INTEGRATION_TYPE_YODLEE)->where('auto_sync', true)->each(function ($bank_integration) use ($company) { // TODO: filter to yodlee only $company->account->bank_integrations->where("integration_type", BankIntegration::INTEGRATION_TYPE_YODLEE)->where('auto_sync', true)->each(function ($bank_integration) use ($company) { // TODO: filter to yodlee only
ProcessBankTransactionsYodlee::dispatch($company->account->id, $bank_integration); ProcessBankTransactionsYodlee::dispatch($company->account->id, $bank_integration);
}); });

View File

@ -260,8 +260,8 @@ class UserController extends BaseController
/** @var \App\Models\User $logged_in_user */ /** @var \App\Models\User $logged_in_user */
$logged_in_user = auth()->user(); $logged_in_user = auth()->user();
$company_user = CompanyUser::whereUserId($user->id) $company_user = CompanyUser::where('user_id',$user->id)
->whereCompanyId($logged_in_user->companyId()) ->where('company_id', $logged_in_user->companyId())
->withTrashed() ->withTrashed()
->first(); ->first();
@ -269,14 +269,10 @@ class UserController extends BaseController
return response()->json(['message', 'Cannot detach owner.'], 401); return response()->json(['message', 'Cannot detach owner.'], 401);
} }
$token = $company_user->token->where('company_id', $company_user->company_id)->where('user_id', $company_user->user_id)->first(); $company_user->tokens()->where('company_id', $company_user->company_id)->where('user_id', $company_user->user_id)->forceDelete();
if ($token) {
$token->delete();
}
if ($company_user) { if ($company_user) {
$company_user->delete(); $company_user->forceDelete();
} }
return response()->json(['message' => ctrans('texts.user_detached')], 200); return response()->json(['message' => ctrans('texts.user_detached')], 200);

View File

@ -47,10 +47,10 @@ class StorePaymentRequest extends Request
'client_id' => ['bail','required',Rule::exists('clients','id')->where('company_id',$user->company()->id)->where('is_deleted', 0)], 'client_id' => ['bail','required',Rule::exists('clients','id')->where('company_id',$user->company()->id)->where('is_deleted', 0)],
'amount' => ['bail', 'numeric', new PaymentAmountsBalanceRule()], 'amount' => ['bail', 'numeric', new PaymentAmountsBalanceRule()],
'invoices.*.amount' => ['bail','required'], 'invoices.*.amount' => ['bail','required'],
'invoices.*.invoice_id' => ['bail','required','distinct',new ValidInvoicesRules($this->all()),Rule::exists('invoices','id')->where('company_id', $user->company()->id)->where('client_id', request()->input('client_id'))], 'invoices.*.invoice_id' => ['bail','required','distinct', new ValidInvoicesRules($this->all()),Rule::exists('invoices','id')->where('company_id', $user->company()->id)->where('client_id', $this->client_id)],
'credits.*.credit_id' => ['bail','required','distinct',new ValidCreditsRules($this->all()),Rule::exists('credits','id')->where('company_id', $user->company()->id)->where('client_id', request()->input('client_id'))], 'credits.*.credit_id' => ['bail','required','distinct', new ValidCreditsRules($this->all()),Rule::exists('credits','id')->where('company_id', $user->company()->id)->where('client_id', $this->client_id)],
'credits.*.amount' => ['bail','required', new CreditsSumRule($this->all())], 'credits.*.amount' => ['bail','required', new CreditsSumRule($this->all())],
'invoices' => ['bail','sometimes','array', new ValidPayableInvoicesRule()], 'invoices' => ['bail','sometimes', 'nullable', 'array', new ValidPayableInvoicesRule()],
'number' => ['bail', 'nullable', Rule::unique('payments')->where('company_id', $user->company()->id)], 'number' => ['bail', 'nullable', Rule::unique('payments')->where('company_id', $user->company()->id)],
'idempotency_key' => ['nullable', 'bail', 'string','max:64', Rule::unique('payments')->where('company_id', $user->company()->id)], 'idempotency_key' => ['nullable', 'bail', 'string','max:64', Rule::unique('payments')->where('company_id', $user->company()->id)],
]; ];

View File

@ -44,10 +44,10 @@ class UpdatePaymentRequest extends Request
$rules = [ $rules = [
'client_id' => ['sometimes', 'bail', Rule::in([$this->payment->client_id])], 'client_id' => ['sometimes', 'bail', Rule::in([$this->payment->client_id])],
'number' => ['sometimes', 'bail', Rule::unique('payments')->where('company_id', $user->company()->id)->ignore($this->payment->id)], 'number' => ['sometimes', 'bail', Rule::unique('payments')->where('company_id', $user->company()->id)->ignore($this->payment->id)],
'invoices' => ['sometimes', 'bail', 'array', new PaymentAppliedValidAmount($this->all())], 'invoices' => ['sometimes', 'bail', 'nullable', 'array', new PaymentAppliedValidAmount($this->all())],
'invoices.*.invoice_id' => ['sometimes','distinct',Rule::exists('invoices','id')->where('company_id', $user->company()->id)->where('client_id', request()->input('client_id'))], 'invoices.*.invoice_id' => ['sometimes','distinct',Rule::exists('invoices','id')->where('company_id', $user->company()->id)->where('client_id', $this->client_id)],
'invoices.*.amount' => ['sometimes','numeric','min:0'], 'invoices.*.amount' => ['sometimes','numeric','min:0'],
'credits.*.credit_id' => ['sometimes','bail','distinct',Rule::exists('credits','id')->where('company_id', $user->company()->id)->where('client_id', request()->input('client_id'))], 'credits.*.credit_id' => ['sometimes','bail','distinct',Rule::exists('credits','id')->where('company_id', $user->company()->id)->where('client_id', $this->client_id)],
'credits.*.amount' => ['required', 'bail'], 'credits.*.amount' => ['required', 'bail'],
]; ];

View File

@ -11,22 +11,21 @@
namespace App\Jobs\EDocument; namespace App\Jobs\EDocument;
use App\Utils\Ninja;
use App\Models\Quote;
use App\Models\Credit; use App\Models\Credit;
use App\Models\Invoice; use App\Models\Invoice;
use App\Models\PurchaseOrder; use App\Models\PurchaseOrder;
use App\Models\Quote;
use App\Services\EInvoicing\Standards\FacturaEInvoice;
use App\Services\EInvoicing\Standards\OrderXDocument;
use App\Services\EInvoicing\Standards\ZugferdEDokument;
use App\Utils\Ninja;
use horstoeko\zugferd\ZugferdDocumentBuilder;
use Illuminate\Bus\Queueable; use Illuminate\Bus\Queueable;
use Illuminate\Support\Facades\App;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue; use horstoeko\zugferd\ZugferdDocumentBuilder;
use Illuminate\Queue\SerializesModels; use App\Services\EDocument\Standards\OrderXDocument;
use Illuminate\Support\Facades\App; use App\Services\EDocument\Standards\FacturaEInvoice;
use function App\Jobs\Invoice\app; use App\Services\EDocument\Standards\ZugferdEDokument;
class CreateEDocument implements ShouldQueue class CreateEDocument implements ShouldQueue
{ {
@ -55,13 +54,14 @@ class CreateEDocument implements ShouldQueue
$t = app('translator'); $t = app('translator');
/* Set the locale*/ /* Set the locale*/
$settings_entity = ($this->document instanceof PurchaseOrder) ? $this->document->vendor : $this->document->client; $settings_entity = ($this->document instanceof PurchaseOrder) ? $this->document->vendor : $this->document->client;
App::setLocale($$settings_entity->locale()); App::setLocale($settings_entity->locale());
/* Set customized translations _NOW_ */ /* Set customized translations _NOW_ */
$t->replace(Ninja::transformTranslations($this->document->client->getMergedSettings())); $t->replace(Ninja::transformTranslations($this->document->client->getMergedSettings()));
$e_document_type = $settings_entity->getSetting('e_invoice_type') ? $settings_entity->getSetting('e_invoice_type') : "XInvoice_3_0"; $e_document_type = strlen($settings_entity->getSetting('e_invoice_type')) > 2 ? $settings_entity->getSetting('e_invoice_type') : "XInvoice_3_0";
$e_quote_type = $settings_entity->getSetting('e_quote_type') ? $settings_entity->getSetting('e_quote_type') : "OrderX_Extended"; $e_quote_type = strlen($settings_entity->getSetting('e_quote_type')) > 2 ? $settings_entity->getSetting('e_quote_type') : "OrderX_Extended";
if ($this->document instanceof Invoice){ if ($this->document instanceof Invoice){
switch ($e_document_type) { switch ($e_document_type) {
case "EN16931": case "EN16931":

View File

@ -222,6 +222,8 @@ class RequiredClientInfo extends Component
$this->show_form = true; $this->show_form = true;
$hash = Cache::get(request()->input('hash')); $hash = Cache::get(request()->input('hash'));
/** @var \App\Models\Invoice $invoice */
$invoice = Invoice::find($this->decodePrimaryKey($hash['invoice_id'])); $invoice = Invoice::find($this->decodePrimaryKey($hash['invoice_id']));
$this->invoice_terms = $invoice->terms; $this->invoice_terms = $invoice->terms;

View File

@ -140,7 +140,7 @@ class TemplateEmail extends Mailable
'whitelabel' => $this->client->user->account->isPaid() ? true : false, 'whitelabel' => $this->client->user->account->isPaid() ? true : false,
'logo' => $this->company->present()->logo($settings), 'logo' => $this->company->present()->logo($settings),
'links' => $this->build_email->getAttachmentLinks(), 'links' => $this->build_email->getAttachmentLinks(),
'email_preferences' => (Ninja::isHosted() && in_array($settings->email_sending_method, ['default', 'mailgun'])) ? $this->company->domain() . URL::signedRoute('client.email_preferences', ['entity' => $this->invitation->getEntityString(), 'invitation_key' => $this->invitation->key], absolute: false) : false, 'email_preferences' => (Ninja::isHosted() && $this->invitation && in_array($settings->email_sending_method, ['default', 'mailgun'])) ? $this->company->domain() . URL::signedRoute('client.email_preferences', ['entity' => $this->invitation->getEntityString(), 'invitation_key' => $this->invitation->key], absolute: false) : false,
]); ]);
foreach ($this->build_email->getAttachments() as $file) { foreach ($this->build_email->getAttachments() as $file) {

View File

@ -202,7 +202,6 @@ class CompanyUser extends Pivot
*/ */
public function portalType(): bool public function portalType(): bool
{ {
nlog(isset($this->react_settings->react_notification_link) && $this->react_settings->react_notification_link);
return isset($this->react_settings->react_notification_link) && $this->react_settings->react_notification_link; return isset($this->react_settings->react_notification_link) && $this->react_settings->react_notification_link;
} }

View File

@ -698,7 +698,7 @@ class RecurringInvoice extends BaseModel
public function subscription(): \Illuminate\Database\Eloquent\Relations\BelongsTo public function subscription(): \Illuminate\Database\Eloquent\Relations\BelongsTo
{ {
return $this->belongsTo(Subscription::class); return $this->belongsTo(Subscription::class)->withTrashed();
} }
public function translate_entity() public function translate_entity()

View File

@ -226,6 +226,7 @@ class User extends Authenticatable implements MustVerifyEmail
return $truth->getCompanyToken(); return $truth->getCompanyToken();
} }
// if (request()->header('X-API-TOKEN')) {
if (request()->header('X-API-TOKEN')) { if (request()->header('X-API-TOKEN')) {
return CompanyToken::with(['cu'])->where('token', request()->header('X-API-TOKEN'))->first(); return CompanyToken::with(['cu'])->where('token', request()->header('X-API-TOKEN'))->first();
} }

View File

@ -41,6 +41,7 @@ use Laracasts\Presenter\PresentableTrait;
* @property string|null $phone * @property string|null $phone
* @property string|null $private_notes * @property string|null $private_notes
* @property string|null $website * @property string|null $website
* @property string|null $routing_id
* @property bool $is_deleted * @property bool $is_deleted
* @property string|null $vat_number * @property string|null $vat_number
* @property string|null $transaction_name * @property string|null $transaction_name

View File

@ -579,6 +579,8 @@ class BaseDriver extends AbstractPaymentDriver
$nmo->company = $this->client->company; $nmo->company = $this->client->company;
$nmo->settings = $this->client->company->settings; $nmo->settings = $this->client->company->settings;
if($this->payment_hash)
{
$invoices = Invoice::query()->whereIn('id', $this->transformKeys(array_column($this->payment_hash->invoices(), 'invoice_id')))->withTrashed()->get(); $invoices = Invoice::query()->whereIn('id', $this->transformKeys(array_column($this->payment_hash->invoices(), 'invoice_id')))->withTrashed()->get();
$invoices->first()->invitations->each(function ($invitation) use ($nmo) { $invoices->first()->invitations->each(function ($invitation) use ($nmo) {
@ -587,6 +589,7 @@ class BaseDriver extends AbstractPaymentDriver
NinjaMailerJob::dispatch($nmo); NinjaMailerJob::dispatch($nmo);
} }
}); });
}
$message = [ $message = [
'server_response' => $response, 'server_response' => $response,

View File

@ -252,6 +252,19 @@ class PaytracePaymentDriver extends BaseDriver
return false; return false;
} }
public function getClientRequiredFields(): array
{
$fields = parent::getClientRequiredFields();
$fields[] = ['name' => 'client_address_line_1', 'label' => ctrans('texts.address1'), 'type' => 'text', 'validation' => 'required'];
$fields[] = ['name' => 'client_city', 'label' => ctrans('texts.city'), 'type' => 'text', 'validation' => 'required'];
$fields[] = ['name' => 'client_postal_code', 'label' => ctrans('texts.postal_code'), 'type' => 'text', 'validation' => 'required'];
$fields[] = ['name' => 'client_state', 'label' => ctrans('texts.state'), 'type' => 'text', 'validation' => 'required'];
$fields[] = ['name' => 'client_country_id', 'label' => ctrans('texts.country'), 'type' => 'text', 'validation' => 'required'];
return $fields;
}
public function auth(): bool public function auth(): bool
{ {
try { try {

View File

@ -206,6 +206,7 @@ class UserRepository extends BaseRepository
->first(); ->first();
$cu->restore(); $cu->restore();
$cu->tokens()->restore();
event(new UserWasRestored($user, auth()->user(), auth()->user()->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null))); event(new UserWasRestored($user, auth()->user(), auth()->user()->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
} }

View File

@ -9,7 +9,7 @@
* @license https://www.elastic.co/licensing/elastic-license * @license https://www.elastic.co/licensing/elastic-license
*/ */
namespace App\Services\EInvoicing\Standards; namespace App\Services\EDocument\Standards;
use App\Models\Invoice; use App\Models\Invoice;
use App\Models\PaymentType; use App\Models\PaymentType;

View File

@ -9,7 +9,7 @@
* @license https://www.elastic.co/licensing/elastic-license * @license https://www.elastic.co/licensing/elastic-license
*/ */
namespace App\Services\EInvoicing\Standards; namespace App\Services\EDocument\Standards;
use App\Models\Invoice; use App\Models\Invoice;
use App\Services\AbstractService; use App\Services\AbstractService;

View File

@ -9,7 +9,7 @@
* @license https://www.elastic.co/licensing/elastic-license * @license https://www.elastic.co/licensing/elastic-license
*/ */
namespace App\Services\EInvoicing\Standards; namespace App\Services\EDocument\Standards;
use App\Models\Credit; use App\Models\Credit;
use App\Models\Invoice; use App\Models\Invoice;

View File

@ -9,7 +9,7 @@
* @license https://www.elastic.co/licensing/elastic-license * @license https://www.elastic.co/licensing/elastic-license
*/ */
namespace App\Services\EInvoicing\Standards; namespace App\Services\EDocument\Standards;
use App\Models\Invoice; use App\Models\Invoice;
use App\Services\AbstractService; use App\Services\AbstractService;

View File

@ -9,7 +9,7 @@
* @license https://www.elastic.co/licensing/elastic-license * @license https://www.elastic.co/licensing/elastic-license
*/ */
namespace App\Services\EInvoicing\Standards; namespace App\Services\EDocument\Standards;
use App\Models\Credit; use App\Models\Credit;
use App\Models\Invoice; use App\Models\Invoice;

View File

@ -94,7 +94,7 @@ class PurchaseOrderService
// if (Ninja::isHosted() && Storage::disk('public')->exists($this->invoice->client->e_invoice_filepath($invitation).$this->invoice->getFileName("xml"))) { // if (Ninja::isHosted() && Storage::disk('public')->exists($this->invoice->client->e_invoice_filepath($invitation).$this->invoice->getFileName("xml"))) {
if (Ninja::isHosted()) { if (Ninja::isHosted()) {
Storage::disk('public')->delete($this->purchase_order->->vendor->e_document_filepath($invitation).$this->purchase_order->getFileName("xml")); Storage::disk('public')->delete($this->purchase_order->vendor->e_document_filepath($invitation).$this->purchase_order->getFileName("xml"));
} }
} catch (\Exception $e) { } catch (\Exception $e) {
nlog($e->getMessage()); nlog($e->getMessage());

View File

@ -109,7 +109,10 @@ class UserTransformer extends EntityTransformer
$transformer = new CompanyUserTransformer($this->serializer); $transformer = new CompanyUserTransformer($this->serializer);
$cu = $user->company_users()->whereCompanyId($user->company_id)->first(); $cu = $user->company_users()->where('company_id',$user->company_id)->first();
if(!$cu)
return null;
return $this->includeItem($cu, $transformer, CompanyUser::class); return $this->includeItem($cu, $transformer, CompanyUser::class);
} }

View File

@ -105,6 +105,7 @@ class VendorTransformer extends EntityTransformer
'language_id' => (string) $vendor->language_id ?: '', 'language_id' => (string) $vendor->language_id ?: '',
'classification' => (string) $vendor->classification ?: '', 'classification' => (string) $vendor->classification ?: '',
'display_name' => (string) $vendor->present()->name(), 'display_name' => (string) $vendor->present()->name(),
'routing_id' => (string) $vendor->routing_id ?: '',
]; ];
} }
} }

View File

@ -14,11 +14,20 @@ return new class extends Migration {
{ {
Schema::table('vendors', function (Blueprint $table) { Schema::table('vendors', function (Blueprint $table) {
$table->string('routing_id')->default(null)->nullable(); $table->string('routing_id')->nullable();
}); });
Schema::table('companies', function (Blueprint $table) {
$table->string('e_quote_type')->default("OrderX_Comfort"); \App\Models\Company::query()
->cursor()
->each(function ($c){
$settings = $c->settings;
$settings->e_quote_type = 'OrderX_Comfort';
$settings->enable_rappen_rounding = false;
$c->settings = $settings;
$c->save();
}); });
} }
/** /**

View File

@ -461,8 +461,8 @@ $lang = array(
'delete_token' => 'Delete Token', 'delete_token' => 'Delete Token',
'token' => 'Token', 'token' => 'Token',
'add_gateway' => 'Add Payment Gateway', 'add_gateway' => 'Add Payment Gateway',
'delete_gateway' => 'Delete Gateway', 'delete_gateway' => 'Delete Payment Gateway',
'edit_gateway' => 'Edit Gateway', 'edit_gateway' => 'Edit Payment Gateway',
'updated_gateway' => 'Successfully updated gateway', 'updated_gateway' => 'Successfully updated gateway',
'created_gateway' => 'Successfully created gateway', 'created_gateway' => 'Successfully created gateway',
'deleted_gateway' => 'Successfully deleted gateway', 'deleted_gateway' => 'Successfully deleted gateway',
@ -5264,6 +5264,10 @@ $lang = array(
'accept_payments_online' => 'Accept Payments Online', 'accept_payments_online' => 'Accept Payments Online',
'all_payment_gateways' => 'View all payment gateways', 'all_payment_gateways' => 'View all payment gateways',
'product_cost' => 'Product cost', 'product_cost' => 'Product cost',
'enable_rappen_roudning' => 'Enable Rappen Rounding',
'enable_rappen_rounding_help' => 'Rounds totals to nearest 5',
'duration_words' => 'Duration in words',
'upcoming_recurring_invoices' => 'Upcoming Recurring Invoices',
); );
return $lang; return $lang;

View File

@ -2194,6 +2194,8 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette
'encryption' => 'Cryptage', 'encryption' => 'Cryptage',
'mailgun_domain' => 'Domaine Mailgun', 'mailgun_domain' => 'Domaine Mailgun',
'mailgun_private_key' => 'Clé privée Mailgun', 'mailgun_private_key' => 'Clé privée Mailgun',
'brevo_domain' => 'Domaine Brevo',
'brevo_private_key' => 'Clé privée Brevo',
'send_test_email' => 'Envoyer un courriel test', 'send_test_email' => 'Envoyer un courriel test',
'select_label' => 'Sélectionnez le libellé', 'select_label' => 'Sélectionnez le libellé',
'label' => 'Libellé', 'label' => 'Libellé',
@ -4844,6 +4846,7 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette
'email_alignment' => 'Justification du courriel', 'email_alignment' => 'Justification du courriel',
'pdf_preview_location' => 'Emplacement de prévisualisation du PDF', 'pdf_preview_location' => 'Emplacement de prévisualisation du PDF',
'mailgun' => 'Mailgun', 'mailgun' => 'Mailgun',
'brevo' => 'Brevo',
'postmark' => 'Postmark', 'postmark' => 'Postmark',
'microsoft' => 'Microsoft', 'microsoft' => 'Microsoft',
'click_plus_to_create_record' => 'Cliquez sur + pour créer un enregistrement', 'click_plus_to_create_record' => 'Cliquez sur + pour créer un enregistrement',
@ -5096,6 +5099,8 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette
'drop_files_here' => 'Déposez les fichiers ici', 'drop_files_here' => 'Déposez les fichiers ici',
'upload_files' => 'Téléverser les fichiers', 'upload_files' => 'Téléverser les fichiers',
'download_e_invoice' => 'Télécharger la facture électronique', 'download_e_invoice' => 'Télécharger la facture électronique',
'download_e_credit' => 'Télécharger E-Credit',
'download_e_quote' => 'Télécharger E-Quote',
'triangular_tax_info' => 'Transactions intra-communautaire triangulaire', 'triangular_tax_info' => 'Transactions intra-communautaire triangulaire',
'intracommunity_tax_info' => 'Livraison intra-communautaure sans taxe', 'intracommunity_tax_info' => 'Livraison intra-communautaure sans taxe',
'reverse_tax_info' => 'Veuillez noter que cette provision est sujette à une charge renversée', 'reverse_tax_info' => 'Veuillez noter que cette provision est sujette à une charge renversée',
@ -5253,6 +5258,9 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette
'select_email_provider' => 'Définir le courriel pour l\'envoi', 'select_email_provider' => 'Définir le courriel pour l\'envoi',
'purchase_order_items' => 'Articles du bon d\'achat', 'purchase_order_items' => 'Articles du bon d\'achat',
'csv_rows_length' => 'Aucune donnée dans ce fichier CSV', 'csv_rows_length' => 'Aucune donnée dans ce fichier CSV',
'accept_payments_online' => 'Accepter les paiements en ligne',
'all_payment_gateways' => 'Voir toutes les passerelles de paiements',
'product_cost' => 'Coût du produit',
); );
return $lang; return $lang;

View File

@ -131,9 +131,9 @@ Route::group(['middleware' => ['invite_db'], 'prefix' => 'client', 'as' => 'clie
Route::get('invoice/{invitation_key}/download_pdf', [InvoiceController::class, 'downloadPdf'])->name('invoice.download_invitation_key')->middleware('token_auth'); Route::get('invoice/{invitation_key}/download_pdf', [InvoiceController::class, 'downloadPdf'])->name('invoice.download_invitation_key')->middleware('token_auth');
Route::get('invoice/{invitation_key}/download_e_invoice', [InvoiceController::class, 'downloadEInvoice'])->name('invoice.download_e_invoice')->middleware('token_auth'); Route::get('invoice/{invitation_key}/download_e_invoice', [InvoiceController::class, 'downloadEInvoice'])->name('invoice.download_e_invoice')->middleware('token_auth');
Route::get('quote/{invitation_key}/download_pdf', [QuoteController::class, 'downloadPdf'])->name('quote.download_invitation_key')->middleware('token_auth'); Route::get('quote/{invitation_key}/download_pdf', [QuoteController::class, 'downloadPdf'])->name('quote.download_invitation_key')->middleware('token_auth');
Route::get('quote/{invitation_key}/download_e_quote', [QuoteController::class, "downloadEQuote"])->name()->name('invoice.download_e_quote')->middleware('token_auth'); Route::get('quote/{invitation_key}/download_e_quote', [QuoteController::class, "downloadEQuote"])->name('invoice.download_e_quote')->middleware('token_auth');
Route::get('credit/{invitation_key}/download_pdf', [CreditController::class, 'downloadPdf'])->name('credit.download_invitation_key')->middleware('token_auth'); Route::get('credit/{invitation_key}/download_pdf', [CreditController::class, 'downloadPdf'])->name('credit.download_invitation_key')->middleware('token_auth');
Route::get('credit/{invitation_key}/download_e_credit', [CreditController::class, 'downloadECredit'])->name('credit.download_invitation_key')->middleware('token_auth'); Route::get('credit/{invitation_key}/download_e_credit', [CreditController::class, 'downloadECredit'])->name('credit.download_e_credit')->middleware('token_auth');
Route::get('{entity}/{invitation_key}/download', [App\Http\Controllers\ClientPortal\InvitationController::class, 'routerForDownload'])->middleware('token_auth'); Route::get('{entity}/{invitation_key}/download', [App\Http\Controllers\ClientPortal\InvitationController::class, 'routerForDownload'])->middleware('token_auth');
Route::get('pay/{invitation_key}', [App\Http\Controllers\ClientPortal\InvitationController::class, 'payInvoice'])->name('pay.invoice'); Route::get('pay/{invitation_key}', [App\Http\Controllers\ClientPortal\InvitationController::class, 'payInvoice'])->name('pay.invoice');

View File

@ -13,7 +13,6 @@ namespace Tests\Feature\EInvoice;
use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Routing\Middleware\ThrottleRequests; use Illuminate\Routing\Middleware\ThrottleRequests;
use Illuminate\Support\Facades\Storage;
use Tests\MockAccountData; use Tests\MockAccountData;
use Tests\TestCase; use Tests\TestCase;
@ -39,7 +38,7 @@ class FacturaeTest extends TestCase
public function testInvoiceGeneration() public function testInvoiceGeneration()
{ {
$f = new \App\Services\EInvoicing\Standards\FacturaEInvoice($this->invoice, "3.2.2"); $f = new \App\Services\EDocument\Standards\FacturaEInvoice($this->invoice, "3.2.2");
$path = $f->run(); $path = $f->run();
$this->assertNotNull($f->run()); $this->assertNotNull($f->run());

View File

@ -11,7 +11,7 @@
namespace Tests\Feature\EInvoice; namespace Tests\Feature\EInvoice;
use App\Services\EInvoicing\Standards\FatturaPA; use App\Services\EDocument\Standards\FatturaPA;
use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Routing\Middleware\ThrottleRequests; use Illuminate\Routing\Middleware\ThrottleRequests;
use Tests\MockAccountData; use Tests\MockAccountData;

View File

@ -420,9 +420,8 @@ class PaymentTest extends TestCase
public function testPaymentRESTEndPoints() public function testPaymentRESTEndPoints()
{ {
Payment::factory()->create(['user_id' => $this->user->id, 'company_id' => $this->company->id, 'client_id' => $this->client->id]); $Payment = Payment::factory()->create(['user_id' => $this->user->id, 'company_id' => $this->company->id, 'client_id' => $this->client->id]);
$Payment->name = \Illuminate\Support\Str::random(54);
$Payment = Payment::all()->last();
$response = $this->withHeaders([ $response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'), 'X-API-SECRET' => config('ninja.api_secret'),
@ -591,19 +590,13 @@ class PaymentTest extends TestCase
$response = false; $response = false;
// try {
$response = $this->withHeaders([ $response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'), 'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token, 'X-API-TOKEN' => $this->token,
])->postJson('/api/v1/payments?include=invoices', $data); ])->postJson('/api/v1/payments?include=invoices', $data);
// } catch (ValidationException $e) {
// $message = json_decode($e->validator->getMessageBag(), 1);
// $this->assertNotNull($message);
// }
// if ($response) {
$response->assertStatus(200); $response->assertStatus(200);
// }
} }
public function testPartialPaymentAmount() public function testPartialPaymentAmount()

View File

@ -61,6 +61,8 @@ class InvoiceTest extends TestCase
'settings' => $c_settings, 'settings' => $c_settings,
]); ]);
$this->assertEquals(0, $c->balance);
$item = InvoiceItemFactory::create(); $item = InvoiceItemFactory::create();
$item->quantity = 1; $item->quantity = 1;
$item->cost = 10.01; $item->cost = 10.01;
@ -88,6 +90,10 @@ class InvoiceTest extends TestCase
$this->assertEquals(10, $ii->amount); $this->assertEquals(10, $ii->amount);
$ii->service()->markSent()->save();
$this->assertEquals(10, $c->fresh()->balance);
} }
public function testRappenRoundingUp() public function testRappenRoundingUp()
@ -129,6 +135,26 @@ class InvoiceTest extends TestCase
$this->assertEquals(10.10, round($ii->amount,2)); $this->assertEquals(10.10, round($ii->amount,2));
$ii->service()->markSent()->save();
$this->assertEquals(10.10, $c->fresh()->balance);
$item = InvoiceItemFactory::create();
$item->quantity = 2;
$item->cost = 10.09;
$item->type_id = '1';
$item->tax_id = '1';
$i->line_items = [$item];
$invoice_calc = new InvoiceSum($i);
$ii = $invoice_calc->build()->getInvoice();
$ii->client->service()->calculateBalance($ii);
$this->assertEquals(20.20, round($ii->amount,2));
$this->assertEquals(20.20, round($ii->balance,2));
$this->assertEquals(20.20, round($c->fresh()->balance,2));
} }
public function testPartialDueDateCast() public function testPartialDueDateCast()