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

Merge pull request #10076 from turbo124/v5-develop

v5.10.30
This commit is contained in:
David Bomba 2024-10-04 12:38:00 +10:00 committed by GitHub
commit 141f45b4ee
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
40 changed files with 3049 additions and 106 deletions

View File

@ -1 +1 @@
5.10.29
5.10.30

View File

@ -18,6 +18,11 @@ class ClientSyncCast implements CastsAttributes
{
public function get($model, string $key, $value, array $attributes)
{
if (is_null($value)) {
return null; // Return null if the value is null
}
$data = json_decode($value, true);
if (!is_array($data)) {

View File

@ -18,6 +18,11 @@ class InvoiceSyncCast implements CastsAttributes
{
public function get($model, string $key, $value, array $attributes)
{
if (is_null($value)) {
return null; // Return null if the value is null
}
$data = json_decode($value, true);
if (!is_array($data)) {

View File

@ -18,6 +18,11 @@ class ProductSyncCast implements CastsAttributes
{
public function get($model, string $key, $value, array $attributes)
{
if (is_null($value)) {
return null; // Return null if the value is null
}
$data = json_decode($value, true);
if (!is_array($data)) {

View File

@ -796,26 +796,26 @@ class CreateSingleAccount extends Command
$cg->save();
}
if (config('ninja.testvars.paypal') && ($this->gateway == 'all' || $this->gateway == 'paypal')) {
$cg = new CompanyGateway();
$cg->company_id = $company->id;
$cg->user_id = $user->id;
$cg->gateway_key = '38f2c48af60c7dd69e04248cbb24c36e';
$cg->require_cvv = true;
$cg->require_billing_address = true;
$cg->require_shipping_address = true;
$cg->update_details = true;
$cg->config = encrypt(config('ninja.testvars.paypal'));
$cg->save();
// if (config('ninja.testvars.paypal') && ($this->gateway == 'all' || $this->gateway == 'paypal')) {
// $cg = new CompanyGateway();
// $cg->company_id = $company->id;
// $cg->user_id = $user->id;
// $cg->gateway_key = '38f2c48af60c7dd69e04248cbb24c36e';
// $cg->require_cvv = true;
// $cg->require_billing_address = true;
// $cg->require_shipping_address = true;
// $cg->update_details = true;
// $cg->config = encrypt(config('ninja.testvars.paypal'));
// $cg->save();
$gateway_types = $cg->driver()->gatewayTypes();
// $gateway_types = $cg->driver()->gatewayTypes();
$fees_and_limits = new stdClass();
$fees_and_limits->{$gateway_types[0]} = new FeesAndLimits();
// $fees_and_limits = new stdClass();
// $fees_and_limits->{$gateway_types[0]} = new FeesAndLimits();
$cg->fees_and_limits = $fees_and_limits;
$cg->save();
}
// $cg->fees_and_limits = $fees_and_limits;
// $cg->save();
// }
if (config('ninja.testvars.paypal_rest') && ($this->gateway == 'all' || $this->gateway == 'paypal_rest')) {
$cg = new CompanyGateway();
@ -881,28 +881,7 @@ class CreateSingleAccount extends Command
$cg->fees_and_limits = $fees_and_limits;
$cg->save();
}
if (config('ninja.testvars.wepay') && ($this->gateway == 'all' || $this->gateway == 'wepay')) {
$cg = new CompanyGateway();
$cg->company_id = $company->id;
$cg->user_id = $user->id;
$cg->gateway_key = '8fdeed552015b3c7b44ed6c8ebd9e992';
$cg->require_cvv = true;
$cg->require_billing_address = true;
$cg->require_shipping_address = true;
$cg->update_details = true;
$cg->config = encrypt(config('ninja.testvars.wepay'));
$cg->save();
$gateway_types = $cg->driver()->gatewayTypes();
$fees_and_limits = new stdClass();
$fees_and_limits->{$gateway_types[0]} = new FeesAndLimits();
$cg->fees_and_limits = $fees_and_limits;
$cg->save();
}
if (config('ninja.testvars.braintree') && ($this->gateway == 'all' || $this->gateway == 'braintree')) {
$cg = new CompanyGateway();
$cg->company_id = $company->id;

View File

@ -284,8 +284,21 @@ class BaseRule implements RuleInterface
public function defaultForeign(): self
{
if($this->invoice->client->is_tax_exempt){
$this->tax_rate1 = 0;
$this->tax_name1 = '';
$this->tax_rate2 = 0;
$this->tax_name2 = '';
if($this->client_region == 'US' && isset($this->tax_data?->taxSales)) {
$this->tax_rate3 = 0;
$this->tax_name3 = '';
return $this;
}
elseif($this->client_region == 'US' && isset($this->tax_data?->taxSales)) {
$this->tax_rate1 = $this->tax_data->taxSales * 100;
$this->tax_name1 = "{$this->tax_data->geoState} Sales Tax";
@ -356,6 +369,16 @@ class BaseRule implements RuleInterface
public function taxExempt($item): self
{
$this->tax_rate1 = 0;
$this->tax_name1 = '';
$this->tax_rate2 = 0;
$this->tax_name2 = '';
$this->tax_rate3 = 0;
$this->tax_name3 = '';
return $this;
}

View File

@ -279,6 +279,15 @@ class InvoiceItemSum
$this->calcTaxesAutomatically();
}
if($this->client->is_tax_exempt){
$this->item->tax_rate1 = 0;
$this->item->tax_rate2 = 0;
$this->item->tax_rate3 = 0;
$this->item->tax_name1 = '';
$this->item->tax_name2 = '';
$this->item->tax_name3 = '';
}
$item_tax = 0;
$amount = $this->item->line_total - ($this->item->line_total * ($this->invoice->discount / 100));

View File

@ -224,6 +224,15 @@ class InvoiceItemSumInclusive
$this->calcTaxesAutomatically();
}
if ($this->client->is_tax_exempt) {
$this->item->tax_rate1 = 0;
$this->item->tax_rate2 = 0;
$this->item->tax_rate3 = 0;
$this->item->tax_name1 = '';
$this->item->tax_name2 = '';
$this->item->tax_name3 = '';
}
$item_tax = 0;
$amount = $this->item->line_total - ($this->item->line_total * ($this->invoice->discount / 100));

View File

@ -127,6 +127,18 @@ class InvoiceSum
private function calculateInvoiceTaxes(): self
{
if($this->client->is_tax_exempt) {
$this->invoice->tax_name1 = '';
$this->invoice->tax_name2 = '';
$this->invoice->tax_name3 = '';
$this->invoice->tax_rate1 = 0;
$this->invoice->tax_rate2 = 0;
$this->invoice->tax_rate3 = 0;
$this->total_taxes = 0;
$this->total_tax_map = [];
return $this;
}
if (is_string($this->invoice->tax_name1) && strlen($this->invoice->tax_name1) >= 2) {
$tax = $this->taxer($this->total, $this->invoice->tax_rate1);
$tax += $this->getSurchargeTaxTotalForKey($this->invoice->tax_name1, $this->invoice->tax_rate1);

View File

@ -129,6 +129,15 @@ class InvoiceSumInclusive
{
$amount = $this->total;
if ($this->client->is_tax_exempt) {
$this->invoice->tax_rate1 = 0;
$this->invoice->tax_rate2 = 0;
$this->invoice->tax_rate3 = 0;
$this->invoice->tax_name1 = '';
$this->invoice->tax_name2 = '';
$this->invoice->tax_name3 = '';
}
if ($this->invoice->discount > 0 && $this->invoice->is_amount_discount) {
$amount = $this->formatValue(($this->sub_total - $this->invoice->discount), 2);
}

View File

@ -50,7 +50,7 @@ class GoCardlessOAuthWebhookController extends Controller
}
}
if ($company_gateway === null) {
if ($company_gateway === null) { //@phpstan-ignore-line
return abort(404);
}

View File

@ -76,7 +76,9 @@ class PingController extends BaseController
public function health()
{
if (Ninja::isNinja()) {
return response()->json(['message' => ctrans('texts.route_not_available'), 'errors' => []], 403);
return response()->json(['message' => '', 'errors' => []], 200);
// return response()->json(['message' => ctrans('texts.route_not_available'), 'errors' => []], 403);
}
return response()->json(SystemHealth::check(), 200);

View File

@ -26,13 +26,15 @@ class SearchController extends Controller
private array $invoices = [];
private array $quotes = [];
public function __invoke(GenericSearchRequest $request)
{
if(config('scount.driver') == 'elastic' && $request->has('search') && $request->input('search') !== '') {
if(config('scout.driver') == 'elastic') {
try{
return $this->search($request->input('search', ''));
return $this->search($request->input('search', '*'));
} catch(\Exception $e) {
nlog("elk down?");
nlog("elk down?" . $e->getMessage());
}
}
@ -136,6 +138,20 @@ class SearchController extends Controller
'id' => $result['_source']['hashed_id'],
'path' => "/clients/{$result['_source']['hashed_id']}"
];
break;
case 'quotes':
if ($result['_source']['__soft_deleted']) { // do not return deleted contacts
break;
}
$this->quotes[] = [
'name' => $result['_source']['name'],
'type' => '/quote',
'id' => $result['_source']['hashed_id'],
'path' => "/quotes/{$result['_source']['hashed_id']}"
];
break;
}
}
@ -251,8 +267,6 @@ class SearchController extends Controller
'custom_fields,vendors' => '/settings/custom_fields/vendors',
'custom_fields,expenses' => '/settings/custom_fields/expenses',
'custom_fields,users' => '/settings/custom_fields/users',
'custom_fields,quotes' => '/settings/custom_fields/quotes',
'custom_fields,credits' => '/settings/custom_fields/credits',
'generated_numbers' => '/settings/generated_numbers',
'client_portal' => '/settings/client_portal',
'email_settings' => '/settings/email_settings',
@ -274,7 +288,7 @@ class SearchController extends Controller
'gateways' => '/settings/online_payments',
'gateways,create' => '/settings/gateways/create',
'bank_accounts,transaction_rules' => '/settings/bank_accounts/transaction_rules',
'bank_accounts,transaction_rules/create' => '/settings/bank_accounts/transaction_rules/create',
'bank_accounts,transaction_rules,create' => '/settings/bank_accounts/transaction_rules/create',
];
$data = [];

View File

@ -211,7 +211,7 @@ class BaseTransformer
public function getClient($client_name, $client_email)
{
if (! empty($client_name)) {
if (strlen($client_name ?? '') >= 1) {
$client_id_search = Client::query()->where('company_id', $this->company->id)
->where('is_deleted', false)
->where('id_number', $client_name);
@ -230,13 +230,13 @@ class BaseTransformer
return $client_name_search->first()->id;
}
}
if (! empty($client_email)) {
if (strlen($client_email ?? '' ) >= 1) {
$contacts = ClientContact::query()->whereHas('client', function ($query) {
$query->where('is_deleted', false);
})
->where('company_id', $this->company->id)
->where('email', $client_email);
if ($contacts->count() >= 1) {
return $contacts->first()->client_id;
}
@ -275,12 +275,14 @@ class BaseTransformer
public function hasClient($name)
{
return Client::query()->where('company_id', $this->company->id)
$x= Client::query()
->where('company_id', $this->company->id)
->where('is_deleted', false)
->whereRaw("LOWER(REPLACE(`name`, ' ' , '')) = ?", [
strtolower(str_replace(' ', '', $name)),
])
->exists();
]);
return $x->exists();
}
public function hasClientIdNumber($id_number)
@ -410,7 +412,8 @@ class BaseTransformer
*/
public function getContact($email): ?ClientContact
{
$contact = ClientContact::query()->where('company_id', $this->company->id)
$contact = ClientContact::query()
->where('company_id', $this->company->id)
->whereRaw("LOWER(REPLACE(`email`, ' ' ,'')) = ?", [
strtolower(str_replace(' ', '', $email)),
])

View File

@ -64,37 +64,37 @@ class InvoiceTransformer extends BaseTransformer
$client_id = null;
if($this->hasClient($this->getString($invoice_data, 'Name') || $this->getContact($this->getString($invoice_data, 'EmailRecipient')))) {
// if($this->hasClient($this->getString($invoice_data, 'Name') || $this->getContact($this->getString($invoice_data, 'EmailRecipient')))) {
$client_id = $this->getClient($this->getString($invoice_data, 'Name'), $this->getString($invoice_data, 'EmailRecipient'));
$client_id = $this->getClient($this->getString($invoice_data, 'Name'), $this->getString($invoice_data, 'EmailRecipient'));
}
// }
if ($client_id) {
$transformed['client_id'] = $client_id;
} else {
$settings = new \stdClass();
$settings->currency_id = $this->getCurrencyByCode($invoice_data, 'Currency');
}
$settings = new \stdClass();
$settings->currency_id = $this->getCurrencyByCode($invoice_data, 'Currency');
$transformed['client'] = [
'name' => $this->getString($invoice_data, 'Name'),
'address1' => $this->getString($invoice_data, 'DocumentRecipientAddress'),
'shipping_address1' => $this->getString($invoice_data, 'ShipAddress'),
'credit_balance' => 0,
'settings' => $settings,
'client_hash' => Str::random(40),
'contacts' => [
[
'email' => $this->getString($invoice_data, 'EmailRecipient'),
],
$transformed['client'] = [
'name' => $this->getString($invoice_data, 'Name'),
'address1' => $this->getString($invoice_data, 'DocumentRecipientAddress'),
'shipping_address1' => $this->getString($invoice_data, 'ShipAddress'),
'credit_balance' => 0,
'settings' => $settings,
'client_hash' => Str::random(40),
'contacts' => [
[
'email' => $this->getString($invoice_data, 'EmailRecipient'),
],
];
],
];
$addresses = $this->harvestAddresses($invoice_data);
$addresses = $this->harvestAddresses($invoice_data);
$transformed['client'] = array_merge($transformed['client'], $addresses);
$transformed['client'] = array_merge($transformed['client'], $addresses);
}
if (! empty($invoice_data['Date Paid'])) {
$transformed['payments'] = [
[

View File

@ -734,7 +734,7 @@ class CompanyImport implements ShouldQueue
{
$this->genericImport(
Client::class,
['user_id', 'assigned_user_id', 'company_id', 'id', 'hashed_id', 'gateway_tokens', 'contacts', 'documents','country'],
['user_id', 'assigned_user_id', 'company_id', 'id', 'hashed_id', 'gateway_tokens', 'contacts', 'documents', 'country', 'sync'],
[['users' => 'user_id'], ['users' => 'assigned_user_id']],
'clients',
'number'
@ -799,7 +799,7 @@ class CompanyImport implements ShouldQueue
{
$this->genericNewClassImport(
Product::class,
['user_id', 'company_id', 'hashed_id', 'id'],
['user_id', 'company_id', 'hashed_id', 'id', 'sync'],
[['users' => 'user_id'], ['users' => 'assigned_user_id'], ['vendors' => 'vendor_id'], ['projects' => 'project_id']],
'products'
);
@ -899,7 +899,7 @@ class CompanyImport implements ShouldQueue
{
$this->genericImport(
Invoice::class,
['user_id', 'client_id', 'company_id', 'id', 'hashed_id', 'recurring_id','status'],
['user_id', 'client_id', 'company_id', 'id', 'hashed_id', 'recurring_id','status', 'sync'],
[
['users' => 'user_id'],
['users' => 'assigned_user_id'],

View File

@ -12,14 +12,15 @@
namespace App\Models;
use Laravel\Scout\Searchable;
use App\DataMapper\ClientSync;
use App\Utils\Traits\AppSetup;
use App\Utils\Traits\MakesHash;
use App\Utils\Traits\MakesDates;
use App\DataMapper\FeesAndLimits;
use App\Models\Traits\Excludable;
use App\DataMapper\ClientSettings;
use App\DataMapper\ClientSync;
use App\DataMapper\CompanySettings;
use Illuminate\Support\Facades\App;
use App\Services\Client\ClientService;
use App\Utils\Traits\GeneratesCounter;
use Laracasts\Presenter\PresentableTrait;
@ -111,7 +112,7 @@ use Illuminate\Contracts\Translation\HasLocalePreference;
* @method static \Illuminate\Database\Eloquent\Builder|Client select()
* @property string $payment_balance
* @property mixed $tax_data
* @property int $is_tax_exempt
* @property bool $is_tax_exempt
* @property bool $has_valid_vat_number
* @mixin \Eloquent
*/
@ -126,8 +127,6 @@ class Client extends BaseModel implements HasLocalePreference
use AppSetup;
use ClientGroupSettingsSaver;
use Excludable;
use Searchable;
protected $presenter = ClientPresenter::class;
@ -241,8 +240,17 @@ class Client extends BaseModel implements HasLocalePreference
public function toSearchableArray()
{
$locale = $this->locale();
App::setLocale($locale);
$name = ctrans('texts.client') . " | " . $this->present()->name();
if(strlen($this->vat_number ?? '') > 1)
$name .= " | ". $this->vat_number;
return [
'name' => $this->present()->name(),
'name' => $name,
'is_deleted' => $this->is_deleted,
'hashed_id' => $this->hashed_id,
'number' => $this->number,
@ -272,6 +280,11 @@ class Client extends BaseModel implements HasLocalePreference
];
}
public function getScoutKey()
{
return $this->hashed_id;
}
public function getEntityType()
{
return self::class;

View File

@ -185,6 +185,11 @@ class ClientContact extends Authenticatable implements HasLocalePreference
];
}
public function getScoutKey()
{
return $this->hashed_id;
}
/*
V2 type of scope
*/

View File

@ -11,12 +11,13 @@
namespace App\Models;
use App\DataMapper\InvoiceSync;
use App\Utils\Ninja;
use Laravel\Scout\Searchable;
use Illuminate\Support\Carbon;
use App\DataMapper\InvoiceSync;
use App\Utils\Traits\MakesDates;
use App\Helpers\Invoice\InvoiceSum;
use Illuminate\Support\Facades\App;
use App\Utils\Traits\MakesReminders;
use App\Utils\Traits\NumberFormatter;
use App\Services\Ledger\LedgerService;
@ -29,6 +30,7 @@ use App\Helpers\Invoice\InvoiceSumInclusive;
use App\Utils\Traits\Invoice\ActionsInvoice;
use Illuminate\Database\Eloquent\SoftDeletes;
use App\Events\Invoice\InvoiceReminderWasEmailed;
use App\Utils\Number;
/**
* App\Models\Invoice
@ -146,7 +148,6 @@ class Invoice extends BaseModel
use MakesInvoiceValues;
use MakesReminders;
use ActionsInvoice;
use Searchable;
protected $presenter = EntityPresenter::class;
@ -244,8 +245,11 @@ class Invoice extends BaseModel
public function toSearchableArray()
{
$locale = $this->company->locale();
App::setLocale($locale);
return [
'name' => $this->client->present()->name() . ' - ' . $this->number,
'name' => ctrans('texts.invoice') . " " . $this->number . " | " . $this->client->present()->name() . ' | ' . Number::formatMoney($this->amount, $this->company) . ' | ' . $this->translateDate($this->date, $this->company->date_format(), $locale),
'hashed_id' => $this->hashed_id,
'number' => $this->number,
'is_deleted' => $this->is_deleted,
@ -253,14 +257,20 @@ class Invoice extends BaseModel
'balance' => (float) $this->balance,
'due_date' => $this->due_date,
'date' => $this->date,
'custom_value1' => $this->custom_value1,
'custom_value2' => $this->custom_value2,
'custom_value3' => $this->custom_value3,
'custom_value4' => $this->custom_value4,
'custom_value1' => (string)$this->custom_value1,
'custom_value2' => (string)$this->custom_value2,
'custom_value3' => (string)$this->custom_value3,
'custom_value4' => (string)$this->custom_value4,
'company_key' => $this->company->company_key,
'po_number' => (string)$this->po_number,
];
}
public function getScoutKey()
{
return $this->hashed_id;
}
public function getEntityType()
{
return self::class;

View File

@ -42,7 +42,7 @@ class ClientContactPresenter extends EntityPresenter
public function search_display()
{
return $this->name().' <'.$this->entity->email.'>' ?? '';
return strlen($this->entity->email ?? '') > 2 ? $this->name().' <'.$this->entity->email.'>' : $this->name();
}
public function phone()

View File

@ -55,6 +55,7 @@ use Laracasts\Presenter\PresentableTrait;
* @property string|null $id_number
* @property int|null $language_id
* @property int|null $last_login
* @property bool $is_tax_exempt
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Activity> $activities
* @property-read int|null $activities_count
* @property-read \App\Models\User|null $assigned_user
@ -116,6 +117,7 @@ class Vendor extends BaseModel
'number',
'language_id',
'classification',
'is_tax_exempt',
];
protected $casts = [

View File

@ -143,6 +143,7 @@ class ACH implements MethodInterface, LivewireMethodInterface
$result = $this->braintree->gateway->transaction()->sale([
'amount' => $this->braintree->payment_hash->data->amount_with_fee,
'paymentMethodToken' => $token->token,
'channel' => 'invoiceninja_BT',
'options' => [
'submitForSettlement' => true,
],

View File

@ -115,6 +115,7 @@ class CreditCard implements LivewireMethodInterface
'options' => [
'submitForSettlement' => true,
],
'channel' => 'invoiceninja_BT',
'billing' => [
'streetAddress' => $this->braintree->client->address1 ?: '',
'extendedAddress' => $this->braintree->client->address2 ?: '',

View File

@ -72,6 +72,7 @@ class PayPal implements LivewireMethodInterface
'amount' => $this->braintree->payment_hash->data->amount_with_fee,
'paymentMethodToken' => $token,
'deviceData' => $state['client-data'],
'channel' => 'invoiceninja_BT',
'options' => [
'submitForSettlement' => true,
'paypal' => [

View File

@ -202,6 +202,9 @@ class BaseRepository
$model->saveQuietly();
if(method_exists($model, 'searchable'))
$model->searchable();
/* Model now persisted, now lets do some child tasks */
if ($model instanceof Invoice) {

View File

@ -95,8 +95,16 @@ class UpdateInvoicePayment
if (property_exists($this->payment_hash->data, 'pre_payment') && $this->payment_hash->data->pre_payment == "1") {
$invoice->payments()->each(function ($p) {
$p->pivot->forceDelete();
$p->invoices()->each(function ($i){
$i->pivot->forceDelete();
});
});
$invoice
->ledger()
->updateInvoiceBalance($paid_amount*-1, "Prepayment Balance Adjustment");
$invoice->is_deleted = true;
$invoice->deleted_at = now();
$invoice->saveQuietly();

View File

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

View File

@ -21,13 +21,17 @@ class NinjaPdf
{
$client = new \GuzzleHttp\Client(['headers' => [
'X-Ninja-Token' => 'test_token_for_now',
],
'X-URL' => config('ninja.app_url'),
],
]);
$response = $client->post($this->url, [
RequestOptions::JSON => ['html' => $html],
]);
return $response->getBody()->getContents();
}
}

View File

@ -229,7 +229,10 @@ class HtmlEngine
$data['$status_logo'] = ['value' => '<div class="stamp is-paid"> ' . ctrans('texts.paid') .'</div>', 'label' => ''];
$data['$show_paid_stamp'] = ['value' => $this->entity->status_id == 4 && $this->settings->show_paid_stamp ? 'flex' : 'none', 'label' => ''];
if($this->entity->status_id == 5)
$data['$status_logo'] = ['value' => '<div class="stamp is-paid"> ' . ctrans('texts.cancelled') .'</div>', 'label' => ''];
$data['$show_paid_stamp'] = ['value' => in_array($this->entity->status_id, [4,5]) && $this->settings->show_paid_stamp ? 'flex' : 'none', 'label' => ''];
$data['$invoice.vendor'] = ['value' => $this->entity->vendor?->present()->name() ?: '', 'label' => ctrans('texts.vendor_name')];

View File

@ -1,5 +1,5 @@
<?php declare(strict_types=1);
return [
'refresh_documents' => env('ELASTIC_SCOUT_DRIVER_REFRESH_DOCUMENTS', false),
'refresh_documents' => env('ELASTIC_SCOUT_DRIVER_REFRESH_DOCUMENTS', true),
];

View File

@ -17,8 +17,8 @@ return [
'require_https' => env('REQUIRE_HTTPS', true),
'app_url' => rtrim(env('APP_URL', ''), '/'),
'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
'app_version' => env('APP_VERSION', '5.10.29'),
'app_tag' => env('APP_TAG', '5.10.29'),
'app_version' => env('APP_VERSION', '5.10.30'),
'app_tag' => env('APP_TAG', '5.10.30'),
'minimum_client_version' => '5.0.16',
'terms_version' => '1.0.1',
'api_secret' => env('API_SECRET', false),

View File

@ -0,0 +1,26 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('vendors', function (Blueprint $table){
$table->boolean('is_tax_exempt')->default(false);
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
//
}
};

File diff suppressed because it is too large Load Diff

View File

@ -224,6 +224,7 @@ CREATE TABLE `bank_transaction_rules` (
`created_at` timestamp(6) NULL DEFAULT NULL,
`updated_at` timestamp(6) NULL DEFAULT NULL,
`deleted_at` timestamp(6) NULL DEFAULT NULL,
`on_credit_match` enum('create_payment','link_payment') NOT NULL DEFAULT 'create_payment',
PRIMARY KEY (`id`),
KEY `bank_transaction_rules_user_id_foreign` (`user_id`),
KEY `bank_transaction_rules_company_id_foreign` (`company_id`),
@ -447,6 +448,7 @@ CREATE TABLE `clients` (
`has_valid_vat_number` tinyint(1) NOT NULL DEFAULT 0,
`classification` varchar(191) DEFAULT NULL,
`e_invoice` mediumtext DEFAULT NULL,
`sync` text DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `clients_company_id_number_unique` (`company_id`,`number`),
KEY `clients_company_id_deleted_at_index` (`company_id`,`deleted_at`),
@ -558,6 +560,16 @@ CREATE TABLE `companies` (
`smtp_local_domain` varchar(191) DEFAULT NULL,
`smtp_verify_peer` tinyint(1) NOT NULL DEFAULT 1,
`e_invoice` mediumtext DEFAULT NULL,
`expense_mailbox_active` tinyint(1) NOT NULL DEFAULT 0,
`expense_mailbox` varchar(191) DEFAULT NULL,
`inbound_mailbox_allow_company_users` tinyint(1) NOT NULL DEFAULT 0,
`inbound_mailbox_allow_vendors` tinyint(1) NOT NULL DEFAULT 0,
`inbound_mailbox_allow_clients` tinyint(1) NOT NULL DEFAULT 0,
`inbound_mailbox_allow_unknown` tinyint(1) NOT NULL DEFAULT 0,
`inbound_mailbox_whitelist` text DEFAULT NULL,
`inbound_mailbox_blacklist` text DEFAULT NULL,
`quickbooks` text DEFAULT NULL,
`legal_entity_id` bigint(20) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `companies_company_key_unique` (`company_key`),
KEY `companies_industry_id_foreign` (`industry_id`),
@ -608,6 +620,7 @@ CREATE TABLE `company_gateways` (
`require_custom_value3` tinyint(1) NOT NULL DEFAULT 0,
`require_custom_value4` tinyint(1) NOT NULL DEFAULT 0,
`always_show_required_fields` tinyint(1) NOT NULL DEFAULT 1,
`settings` text DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `company_gateways_company_id_deleted_at_index` (`company_id`,`deleted_at`),
KEY `company_gateways_gateway_key_foreign` (`gateway_key`),
@ -703,12 +716,12 @@ CREATE TABLE `countries` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`capital` varchar(255) DEFAULT NULL,
`citizenship` varchar(255) DEFAULT NULL,
`country_code` varchar(3) DEFAULT NULL,
`country_code` varchar(4) NOT NULL,
`currency` varchar(255) DEFAULT NULL,
`currency_code` varchar(255) DEFAULT NULL,
`currency_sub_unit` varchar(255) DEFAULT NULL,
`full_name` varchar(255) DEFAULT NULL,
`iso_3166_2` varchar(2) DEFAULT NULL,
`iso_3166_2` varchar(5) NOT NULL,
`iso_3166_3` varchar(3) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
`region_code` varchar(3) DEFAULT NULL,
@ -1193,6 +1206,8 @@ CREATE TABLE `invoices` (
`is_proforma` tinyint(1) NOT NULL DEFAULT 0,
`tax_data` mediumtext DEFAULT NULL,
`e_invoice` mediumtext DEFAULT NULL,
`sync` text DEFAULT NULL,
`gateway_fee` decimal(13,6) NOT NULL DEFAULT 0.000000,
PRIMARY KEY (`id`),
UNIQUE KEY `invoices_company_id_number_unique` (`company_id`,`number`),
KEY `invoices_user_id_foreign` (`user_id`),
@ -1201,6 +1216,7 @@ CREATE TABLE `invoices` (
KEY `invoices_company_id_index` (`company_id`),
KEY `invoices_recurring_id_index` (`recurring_id`),
KEY `invoices_status_id_balance_index` (`status_id`,`balance`),
KEY `invoices_project_id_deleted_at_index` (`project_id`,`deleted_at`),
CONSTRAINT `invoices_client_id_foreign` FOREIGN KEY (`client_id`) REFERENCES `clients` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `invoices_company_id_foreign` FOREIGN KEY (`company_id`) REFERENCES `companies` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `invoices_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
@ -1247,8 +1263,10 @@ CREATE TABLE `licenses` (
`transaction_reference` varchar(191) DEFAULT NULL,
`product_id` int(10) unsigned DEFAULT NULL,
`recurring_invoice_id` bigint(20) unsigned DEFAULT NULL,
`e_invoice_quota` int(10) unsigned DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `licenses_license_key_unique` (`license_key`)
UNIQUE KEY `licenses_license_key_unique` (`license_key`),
KEY `licenses_e_invoice_quota_index` (`e_invoice_quota`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `migrations`;
@ -1286,6 +1304,7 @@ CREATE TABLE `payment_hashes` (
PRIMARY KEY (`id`),
KEY `payment_hashes_payment_id_foreign` (`payment_id`),
KEY `payment_hashes_hash_index` (`hash`),
KEY `payment_hashes_fee_invoice_id_index` (`fee_invoice_id`),
CONSTRAINT `payment_hashes_payment_id_foreign` FOREIGN KEY (`payment_id`) REFERENCES `payments` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
@ -1446,6 +1465,8 @@ CREATE TABLE `products` (
`max_quantity` int(10) unsigned DEFAULT NULL,
`product_image` varchar(191) DEFAULT NULL,
`tax_id` int(10) unsigned DEFAULT NULL,
`hash` varchar(191) DEFAULT NULL,
`sync` text DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `products_company_id_deleted_at_index` (`company_id`,`deleted_at`),
KEY `products_user_id_foreign` (`user_id`),
@ -1718,6 +1739,7 @@ CREATE TABLE `quotes` (
KEY `quotes_client_id_index` (`client_id`),
KEY `quotes_company_id_index` (`company_id`),
KEY `quotes_company_id_updated_at_index` (`company_id`,`updated_at`),
KEY `quotes_project_id_deleted_at_index` (`project_id`,`deleted_at`),
CONSTRAINT `quotes_client_id_foreign` FOREIGN KEY (`client_id`) REFERENCES `clients` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `quotes_company_id_foreign` FOREIGN KEY (`company_id`) REFERENCES `companies` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `quotes_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
@ -2082,6 +2104,7 @@ CREATE TABLE `subscriptions` (
`optional_product_ids` text DEFAULT NULL,
`optional_recurring_product_ids` text DEFAULT NULL,
`steps` varchar(191) DEFAULT NULL,
`remaining_cycles` int(11) DEFAULT -1,
PRIMARY KEY (`id`),
UNIQUE KEY `subscriptions_company_id_name_unique` (`company_id`,`name`),
KEY `billing_subscriptions_company_id_deleted_at_index` (`company_id`,`deleted_at`),
@ -2670,3 +2693,20 @@ INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (237,'2024_06_02_08
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (238,'2024_06_04_123926_2024_06_04_fixes_for_btc_migration',2);
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (239,'2024_06_08_043343_2024_06_08__i_s_k_currency_precision',2);
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (240,'2024_06_19_015127_2024_06_19_referral_meta_data',2);
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (241,'2023_12_10_110951_inbound_mail_parsing',3);
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (242,'2024_06_11_231143_add_rotessa_gateway',3);
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (243,'2024_06_23_040253_2024-06-23_indexesforinvoiceid_payment_hashes',3);
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (244,'2024_07_10_043241_2024_07_10_invoice_id_index_on_projects_table',3);
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (245,'2024_07_16_231556_2024_07_17_add_dubai_timezone',3);
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (246,'2024_07_29_235430_2024_30_07_tax_model_migration',3);
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (247,'2024_08_02_144614_alter_companies_quickbooks',3);
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (248,'2024_08_04_225558_tax_model_migration_v2',3);
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (249,'2024_08_21_001832_add_einvoice_option_license',3);
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (250,'2024_08_26_055523_add_qb_product_hash',3);
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (251,'2024_08_27_230111_blockonomics_gateway',3);
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (252,'2024_09_06_042040_cba_powerboard',3);
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (253,'2024_09_15_022436_add_autonomous_es_regions',3);
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (254,'2024_09_16_221343_add_remaining_cycles_to_subscriptions',3);
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (255,'2024_09_21_062105_2024_09_21_add_vn_lang',3);
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (256,'2024_09_22_084749_2024_09_23_add_sync_column_for_qb',3);
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (257,'2024_09_29_221552_add_gateway_fee_column',4);

View File

@ -5336,6 +5336,24 @@ Développe automatiquement la section des notes dans le tableau de produits pour
'no_unread_notifications' => 'Vous êtes à jour! Aucune nouvelle notification.',
'how_to_import_data' => 'Comment importer vos données',
'download_example_file' => 'Télécharger un fichier exemple',
'expense_mailbox' => 'Adresse courriel entrante',
'expense_mailbox_help' => 'L\'adresse courriel entrante qui accepte les documents de dépenses, ex. depense@invoiceninja.com.',
'expense_mailbox_active' => 'Boîte de réception de dépense',
'expense_mailbox_active_help' => 'Permet de traiter des documents tels que des reçus pour le rapport de dépenses.',
'inbound_mailbox_allow_company_users' => 'Permettre les envois de l\'entreprise',
'inbound_mailbox_allow_company_users_help' => 'Permet aux utilisateurs au sein de l\'entreprise d\'envoyer des documents de dépenses.',
'inbound_mailbox_allow_vendors' => 'Permettre les envois de fournisseurs',
'inbound_mailbox_allow_vendors_help' => 'Permet aux fournisseurs de l\'entreprise d\'envoyer des documents de dépenses.',
'inbound_mailbox_allow_clients' => 'Permettre les envois de clients',
'inbound_mailbox_allow_clients_help' => 'Permet aux clients d\'envoyer des documents de dépenses.',
'inbound_mailbox_whitelist' => 'Liste d\'expéditeurs entrants autorisés',
'inbound_mailbox_whitelist_help' => 'Liste d\'adresses courriel séparées par des virgules qui devraient être autorisées à envoyer des courriels pour traitement.',
'inbound_mailbox_blacklist' => 'Liste d\'expéditeurs entrants interdits',
'inbound_mailbox_blacklist_help' => 'Liste d\'adresses électroniques séparées par des virgules qui ne sont pas autorisées à envoyer des courriels pour traitement.',
'inbound_mailbox_allow_unknown' => 'Autoriser tous les envois',
'inbound_mailbox_allow_unknown_help' => 'Autoriser n\'importe qui à envoyer un courriel de dépenses pour traitement.',
'quick_actions' => 'Actions rapides',
'end_all_sessions_help' => 'Déconnecte tous les utilisateurs et oblige tous les utilisateurs actifs à se réauthentifier.'
);
return $lang;

View File

@ -5338,6 +5338,24 @@ $lang = array(
'no_unread_notifications' => 'Bạn đã cập nhật đầy đủ rồi! Không có thông báo mới nào.',
'how_to_import_data' => 'Làm thế nào đến nhập dữ liệu',
'download_example_file' => 'Tải xuống tệp ví dụ',
'expense_mailbox' => 'Địa chỉ email đến',
'expense_mailbox_help' => 'Địa chỉ email đến chấp nhận chứng từ Chi phí . Ví dụ. expense@invoiceninja.com',
'expense_mailbox_active' => 'Chi phí hộp thư',
'expense_mailbox_active_help' => 'Cho phép xử lý các chứng từ như biên lai để báo cáo Chi phí',
'inbound_mailbox_allow_company_users' => 'Cho phép người gửi công ty',
'inbound_mailbox_allow_company_users_help' => 'Cho phép người dùng trong công ty đến chứng từ Chi phí .',
'inbound_mailbox_allow_vendors' => 'Cho phép Người bán Người gửi',
'inbound_mailbox_allow_vendors_help' => 'Cho phép các nhà cung cấp của công ty đến chứng từ Chi phí',
'inbound_mailbox_allow_clients' => 'Cho phép Người gửi Khách hàng',
'inbound_mailbox_allow_clients_help' => 'Cho phép Khách hàng đến gửi tài liệu Chi phí',
'inbound_mailbox_whitelist' => 'Danh sách cho phép người gửi đến',
'inbound_mailbox_whitelist_help' => 'Danh sách các email được phân tách bằng dấu phẩy được phép đến email để xử lý',
'inbound_mailbox_blacklist' => 'Danh sách người gửi bị cấm',
'inbound_mailbox_blacklist_help' => 'Dấu phẩy phân tách danh sách các email không được phép đến email để xử lý',
'inbound_mailbox_allow_unknown' => 'Cho phép tất cả người gửi',
'inbound_mailbox_allow_unknown_help' => 'Cho phép bất cứ ai đến gửi email Chi phí để xử lý',
'quick_actions' => 'Hành động nhanh',
'end_all_sessions_help' => 'Đăng xuất tất cả người dùng và yêu cầu tất cả người dùng đang hoạt động đến xác thực lại.'
);
return $lang;

File diff suppressed because one or more lines are too long

1
public/build/assets/app-9c3f71d4.css vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -372,7 +372,7 @@
"src": "resources/js/setup/setup.js"
},
"resources/sass/app.scss": {
"file": "assets/app-22043157.css",
"file": "assets/app-9c3f71d4.css",
"isEntry": true,
"src": "resources/sass/app.scss"
}

View File

@ -121,9 +121,9 @@ class Invoice2GoTest extends TestCase
$client = Client::find($client_id);
$this->assertInstanceOf(Client::class, $client);
$this->assertEquals('840', $client->country_id);
$this->assertEquals('wade@projectx.net', $client->contacts->first()->email);
$this->assertEquals('2584 Sesame Street', $client->address1);
// $this->assertEquals('840', $client->country_id);
// $this->assertEquals('wade@projectx.net', $client->contacts->first()->email);
// $this->assertEquals('2584 Sesame Street', $client->address1);
$this->assertTrue($base_transformer->hasInvoice('1'));
$this->assertTrue($base_transformer->hasInvoice('2'));